7.1 KiB
IdentityGuardInterceptor — 코어 본인인증 인터셉터 레퍼런스
코어 resources/js/core/identity/IdentityGuardInterceptor.ts 정적 클래스의 공개 API와 동작 계약을 다룹니다. 템플릿 / 플러그인이 IDV 흐름을 wiring 할 때 참조하세요.
TL;DR (5초 요약)
1. ActionDispatcher.handleApiCall 응답 후처리에서 isIdentityRequired/handle 호출 (engine-v1.44.0+)
2. setLauncher(launcher) 로 모달 launcher 등록 — 템플릿 부트스트랩 의무
3. launcher 반환 타입 = Promise<VerificationResult> (engine-v1.46.0+)
4. handle() 가 verified 시 return_request.url 에 ?verification_token=... query 자동 부착 후 fetch
5. defaultLauncher — launcher 미등록 시 토스트 + /identity/challenge?return=... navigate 폴백
6. 인증 대상(email/phone)은 흐름이 apiCall `identity_target` 으로 선언 → handle() 이 payload.target 에 병합 → launcher 가 사용 (engine-v1.51.0+)
정적 API 전체
class IdentityGuardInterceptor {
// 등록 / 진단
static setLauncher(launcher: ModalLauncher): void
static hasLauncher(): boolean
static reset(): void // 테스트 / 진단용
// 응답 감지
static isIdentityRequired(status: number, body: unknown): body is IdentityResponse428
static async handle(
response: IdentityResponse428,
originalRequest?: Pick<RequestInit, 'body' | 'headers' | 'credentials'>,
target?: IdentityVerificationTarget, // engine-v1.51.0+ — 흐름이 선언한 인증 대상
): Promise<Response | null>
// Deferred resolver — 모달 ↔ launcher Promise 통신
static createDeferred(): Promise<VerificationResult>
static resolveDeferred(result: VerificationResult): void
// external_redirect helper
static redirectExternally(payload: VerificationPayload): Promise<VerificationResult>
}
launcher 반환 타입 — VerificationResult
engine-v1.46.0+ — 4-상태 객체로 확장 (이전: Promise<boolean>).
type VerificationResult =
| { status: 'verified'; token: string; providerData?: Record<string, unknown> }
| { status: 'pending'; pollUrl: string; pollIntervalMs?: number; expiresAt: string }
| { status: 'cancelled' }
| { status: 'failed'; failureCode: string; reason?: string };
| 상태 | handle() 동작 |
|---|---|
verified |
return_request.url 에 ?verification_token= 자동 부착 → fetch 재실행 → Response 반환 |
pending |
1차 구현은 failed 로 강등 (caller 에 null 반환). 향후 폴링 루프 도입 시 활용 |
cancelled |
null 반환 — 원 요청 폐기 |
failed |
null 반환 — failureCode 는 caller 가 onError 분기에서 처리 |
verification_token 자동 query 부착
handle() 이 verify 성공 시 return_request.url 에 token 을 query 로 자동 부착:
원 요청: POST /api/auth/register (body: { email, password, ... })
재실행: POST /api/auth/register?verification_token=tok-abc-123 (body: 원본 그대로)
회원가입 폼 등 기존 레이아웃이 query.verification_token 패턴을 사용 중이라면 그대로 호환. 백엔드 IdvTokenRule 은 query/body 어디에 있든 검증.
resolveIdentityChallenge 핸들러 spec
코어 ActionDispatcher 가 등록한 표준 핸들러 — 레이아웃 JSON 에서 직접 호출.
| params | 타입 | 설명 |
|---|---|---|
result |
'verified'|'cancelled'|'failed'|'pending' |
결과 종류 (필수) |
token |
string | result=verified 일 때 verification_token (필수) |
failureCode |
string | result=failed 일 때 — INVALID_CODE / EXPIRED / MAX_ATTEMPTS 등 |
reason |
string | result=failed 의 사람-읽기용 메시지 (선택) |
providerData |
object | provider 가 돌려준 추가 데이터 (선택) |
pollUrl, pollIntervalMs, expiresAt |
— | result=pending 인터페이스 (예약) |
값 누락 시 안전한 기본값으로 강등:
- result=verified 인데 token 누락 →
failed/MISSING_TOKEN - result=pending 인데 pollUrl/expiresAt 누락 →
failed/MALFORMED_PENDING - result 미상 / 오타 →
cancelled
defaultLauncher — launcher 미등록 폴백
외부 템플릿이 setLauncher 미호출 시 코어가 사용하는 폴백:
1. external_redirect 또는 redirect_url 있음 → redirectExternally 위임
2. G7Core.toast: warning("본인 확인이 필요합니다.")
3. sessionStorage stash (return_url + payload)
4. G7Core.dispatch: navigate('/identity/challenge?return=' + encodeURIComponent(currentUrl))
5. Promise<never> — 페이지 unmount
G7Core 미초기화 환경: console.error 만 출력 + failed/G7_NOT_READY 반환.
external_redirect helper — redirectExternally
1. payload.redirect_url 누락 → failed/MISSING_REDIRECT_URL
2. sessionStorage[g7.identity.redirectStash] = JSON({ return_url, payload, stashed_at })
3. window.location.href = redirect_url
4. Promise<never>
콜백 URL(POST /api/identity/callback/{providerId} 처리 후 redirect) 에서 stash 복원 책임은 콜백 처리 레이아웃이 담당.
sessionStorage stash 키
import { IDENTITY_REDIRECT_STASH_KEY } from '../identity/types';
// 또는 window.G7Core.identity.redirectStashKey
// 값: 'g7.identity.redirectStash'
window.G7Core.identity 노출 (engine-v1.46.0+)
템플릿 IIFE 번들이 코어 모듈을 중복 포함하면 정적 클래스 상태가 분리되므로, 직접 import 대신 window.G7Core.identity 를 사용해야 합니다.
// 템플릿 / 플러그인 코드
const identity = (window as any).G7Core?.identity;
if (identity?.setLauncher) {
identity.setLauncher(myLauncher);
}
identity.redirectExternally(payload);
const deferred = identity.createDeferred();
identity.resolveDeferred({ status: 'verified', token });
| 노출 메서드 | 설명 |
|---|---|
setLauncher(launcher) |
모달 launcher 등록 |
hasLauncher() |
등록 여부 |
redirectExternally(payload) |
external_redirect helper |
createDeferred() |
deferred Promise 생성 |
resolveDeferred(result) |
resolver 호출 (resolveIdentityChallenge 핸들러가 내부적으로 사용) |
reset() |
launcher + deferred 슬롯 초기화 (테스트용) |
redirectStashKey |
'g7.identity.redirectStash' 상수 |
동시 launcher 진입 처리
두 번째 createDeferred() 호출 시 이전 deferred 는 자동으로 cancelled 로 강제 종료:
const first = IdentityGuardInterceptor.createDeferred();
const second = IdentityGuardInterceptor.createDeferred(); // first 는 자동 cancelled
IdentityGuardInterceptor.resolveDeferred({ status: 'verified', token: 'tok' });
// first → resolves to { status: 'cancelled' }
// second → resolves to { status: 'verified', token: 'tok' }
관련 문서
- identity-verification-ui.md — 모달 UI / 상태 머신 / Extension Point 슬롯 가이드
- ../extension/template-idv-bootstrap.md — 외부 템플릿 launcher 등록 가이드
- ../backend/identity-policies.md — 백엔드 정책 시스템