인증
각 인증 방법에 대한 DSL 옵션 및 코드 예제입니다. Identity DSL에서 .form(), .rest(), .ott(), .passkey()를 통해 설정하는 인증 방법에 대한 상세 레퍼런스입니다.
개요
Contexa Identity는 4가지 인증 방법을 제공합니다. 각 방법은 독립적인 SecurityFilterChain을 생성하며, 우선순위는 order()를 통해 제어됩니다.
| 인증 방법 | DSL 메서드 | 기본 Order | 용도 |
|---|---|---|---|
| Form Login | .form() | 100 | 기존 웹 폼 로그인 (서버 렌더링) |
| REST API | .rest() | 200 | JSON 기반 API 인증 (SPA, 모바일) |
| One-Time Token | .ott() | 300 | 매직 링크 / 이메일 인증 |
| WebAuthn / Passkey | .passkey() | 400 | 생체 인증 / 하드웨어 키 |
모든 인증 방법은 rawHttp()를 통해 전체 Spring Security API에 접근할 수 있으며, 공통 옵션(order, CSRF, CORS, 헤더, 로그아웃 등)을 지원합니다.
Form Login
기존 웹 폼 기반 로그인입니다. DSL을 통해 Spring Security의 formLogin()을 설정합니다. 기본 order는 100입니다.
전체 옵션
| 메서드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
loginPage(String) | String | 단일 인증에서는 미설정, MFA 빌더에서는 기본 1차 로그인 페이지 적용 | 로그인 페이지 URL |
usernameParameter(String) | String | "username" | 사용자명 파라미터 이름 |
passwordParameter(String) | String | "password" | 비밀번호 파라미터 이름 |
loginProcessingUrl(String) | String | AuthUrlProvider.getSingleFormLoginProcessing() | 로그인 처리 URL |
defaultSuccessUrl(String) | String | - | 로그인 성공 후 리다이렉트 URL |
defaultSuccessUrl(String, boolean) | String, boolean | - | 성공 URL + alwaysUse 플래그 |
failureUrl(String) | String | - | 로그인 실패 시 리다이렉트 URL |
permitAll() | - | false | 로그인 페이지에 대한 미인증 접근 허용 |
successHandler(PlatformAuthenticationSuccessHandler) | Handler | 자동 선택 | 커스텀 성공 핸들러 |
failureHandler(PlatformAuthenticationFailureHandler) | Handler | 자동 선택 | 커스텀 실패 핸들러 |
securityContextRepository(SecurityContextRepository) | Repository | 상태 유형에 따라 자동 선택 | 보안 컨텍스트 리포지토리 |
rawFormLogin(SafeHttpFormLoginCustomizer) | Customizer | - | formLogin() 내부 직접 커스터마이제이션 |
rawHttp(SafeHttpCustomizer<HttpSecurity>) | Customizer | - | 전체 Spring Security API 접근 (누적) |
order(int) | int | 100 | Filter Chain 우선순위 |
asep(Customizer<FormAsepAttributes>) | Customizer | - | ASEP 어노테이션 속성 설정 |
기본 설정
registry
.form(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home")
.failureUrl("/login?error")
.permitAll()
)
.session(Customizer.withDefaults())
.build();
커스텀 핸들러
registry
.form(form -> form
.loginPage("/login")
.usernameParameter("email")
.passwordParameter("passwd")
.successHandler(customSuccessHandler)
.failureHandler(customFailureHandler)
)
.session(Customizer.withDefaults())
.build();
고급 설정 (rawHttp + rawFormLogin)
registry
.form(form -> form
.order(20)
.loginPage("/admin/login")
.rawFormLogin(formLogin -> formLogin
.usernameParameter("admin_user")
.passwordParameter("admin_pass"))
.rawHttp(http -> http
.securityMatcher("/admin/**")
.sessionManagement(session -> session
.maximumSessions(1)
.maxSessionsPreventsLogin(true)))
)
.session(Customizer.withDefaults())
.build();
rawFormLogin()은 HttpSecurity.formLogin()의 내부만 커스터마이즈합니다. rawHttp()는 전체 Spring Security API(sessionManagement, securityMatcher, 커스텀 필터 등록 등)에 대한 접근을 제공합니다. 두 메서드 모두 누적 호출을 지원합니다.
REST API 인증
JSON 기반 REST API 인증입니다. SPA와 모바일 앱 같은 프론트엔드 클라이언트에서 JSON 페이로드로 인증합니다. 기본 order는 200입니다.
전체 옵션
| 메서드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
loginProcessingUrl(String) | String | AuthUrlProvider.getSingleRestLoginProcessing() | REST 로그인 처리 URL |
defaultSuccessUrl(String) | String | - | 성공 후 리다이렉트 URL |
defaultSuccessUrl(String, boolean) | String, boolean | - | 성공 URL + alwaysUse 플래그 |
failureUrl(String) | String | - | 실패 시 리다이렉트 URL |
successHandler(PlatformAuthenticationSuccessHandler) | Handler | 자동 선택 | 커스텀 성공 핸들러 |
failureHandler(PlatformAuthenticationFailureHandler) | Handler | 자동 선택 | 커스텀 실패 핸들러 |
securityContextRepository(SecurityContextRepository) | Repository | 상태 유형에 따라 자동 선택 | 보안 컨텍스트 리포지토리 |
rawHttp(SafeHttpCustomizer<HttpSecurity>) | Customizer | - | 전체 Spring Security API 접근 (누적) |
order(int) | int | 200 | Filter Chain 우선순위 |
asep(Customizer<RestAsepAttributes>) | Customizer | - | ASEP 어노테이션 속성 설정 |
기본 설정
registry
.rest(rest -> rest
.loginProcessingUrl("/api/auth/login")
)
.oauth2(Customizer.withDefaults())
.build();
Stateless API 설정 (rawHttp)
registry
.rest(rest -> rest
.order(50)
.loginProcessingUrl("/api/auth")
.rawHttp(http -> http
.securityMatcher("/api/**")
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)))
)
.oauth2(Customizer.withDefaults())
.build();
REST API 인증은 일반적으로 Stateless JWT 기반 운영을 위해
.oauth2()와 결합됩니다. .session()과도 결합할 수 있지만, API 서버에는 OAuth2를 권장합니다.
One-Time Token (매직 링크)
이메일 또는 SMS로 전송되는 일회용 토큰을 통한 인증입니다. 매직 링크 방식의 비밀번호 없는 인증입니다. 기본 order는 300입니다.
전체 옵션
| 메서드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
tokenGeneratingUrl(String) | String | - | 토큰 생성 요청 URL |
defaultSubmitPageUrl(String) | String | - | 토큰 입력 페이지 URL |
parameter names | String | "username" / "token" | 현재 공개 OTT DSL은 기본 파라미터 이름을 사용합니다. 다른 이름이 필요하면 하위 옵션 커스터마이징이 필요합니다. |
showDefaultSubmitPage(boolean) | boolean | true | 기본 토큰 제출 페이지 표시 여부 |
tokenService(OneTimeTokenService) | Service | 애플리케이션 컨텍스트의 Bean | 토큰 생성/검증 서비스 구현 (필수) |
tokenGenerationSuccessHandler(OneTimeTokenGenerationSuccessHandler) | Handler | - | 토큰 생성 성공 핸들러 (예: 이메일 발송) |
loginProcessingUrl(String) | String | AuthUrlProvider.getSingleOttLoginProcessing() | 토큰 검증 처리 URL |
successHandler(PlatformAuthenticationSuccessHandler) | Handler | 자동 선택 | 인증 성공 핸들러 |
failureHandler(PlatformAuthenticationFailureHandler) | Handler | 자동 선택 | 인증 실패 핸들러 |
rawHttp(SafeHttpCustomizer<HttpSecurity>) | Customizer | - | 전체 Spring Security API 접근 (누적) |
order(int) | int | 300 | Filter Chain 우선순위 |
asep(Customizer<OttAsepAttributes>) | Customizer | - | ASEP 어노테이션 속성 설정 |
기본 설정
registry
.ott(ott -> ott
.tokenService(customTokenService)
.tokenGenerationSuccessHandler(emailSendingHandler)
)
.session(Customizer.withDefaults())
.build();
커스텀 페이지 + 이메일 발송 핸들러
registry
.ott(ott -> ott
.tokenGeneratingUrl("/auth/magic-link/request")
.defaultSubmitPageUrl("/auth/magic-link/verify")
// 현재 공개 OTT DSL은 기본 token 파라미터 이름("token")을 사용합니다.
.showDefaultSubmitPage(false)
.tokenService(jpaOneTimeTokenService)
.tokenGenerationSuccessHandler((request, response, token) -> {
String email = request.getParameter("username");
emailService.sendMagicLink(email, token.getTokenValue());
response.sendRedirect("/auth/magic-link/sent");
})
)
.session(Customizer.withDefaults())
.build();
WebAuthn / Passkey
FIDO2 WebAuthn 기반 생체 인증 및 하드웨어 보안 키 인증입니다. 가장 안전한 비밀번호 없는 인증 방식입니다. 기본 order는 400입니다.
전체 옵션
| 메서드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
rpName(String) | String | "contexa-identity" | Relying Party 이름 (사용자에게 표시) |
rpId(String) | String | "localhost" | Relying Party ID (도메인) |
allowedOrigins(Set<String>) | Set<String> | ["http://localhost:${server.port}"] (명시적 설정이 없을 때의 fallback) | 허용 오리진 목록 |
allowedOrigins(String...) | String... | - | 허용 오리진 (varargs) |
assertionOptionsEndpoint(String) | String | AuthUrlProvider.getSinglePasskeyAssertionOptions() | Assertion 옵션 엔드포인트 |
loginProcessingUrl(String) | String | AuthUrlProvider.getSinglePasskeyLoginProcessing() | 인증 처리 URL |
successHandler(PlatformAuthenticationSuccessHandler) | Handler | 자동 선택 | 인증 성공 핸들러 |
failureHandler(PlatformAuthenticationFailureHandler) | Handler | 자동 선택 | 인증 실패 핸들러 |
rawHttp(SafeHttpCustomizer<HttpSecurity>) | Customizer | - | 전체 Spring Security API 접근 (누적) |
order(int) | int | 400 | Filter Chain 우선순위 |
asep(Customizer<PasskeyAsepAttributes>) | Customizer | - | ASEP 어노테이션 속성 설정 |
기본 설정
registry
.passkey(passkey -> passkey
.rpName("My Application")
.rpId("example.com")
.allowedOrigins("https://example.com")
)
.session(Customizer.withDefaults())
.build();
Passkey 등록 플로우
Passkey 등록은 3단계로 진행됩니다. 서버는 Spring Security의 UserCredentialRepository를 통해 자격 증명을 저장합니다.
Client Server
| |
| 1. POST /webauthn/register |
| /options |
| ---------------------------> |
| | PublicKeyCredentialCreationOptions
| <--------------------------- | (rpId, rpName, userId, challenge)
| |
| 2. navigator.credentials |
| .create(options) |
| [Browser WebAuthn API] |
| |
| 3. POST /webauthn/register |
| ---------------------------> |
| (AuthenticatorAttestation | Verify + Store in
| Response) | UserCredentialRepository
| |
| <--- 201 Created ----------- |
Passkey 관리 REST API
| 메서드 | URL | 설명 |
|---|---|---|
POST | /webauthn/register/options | 등록 옵션 생성 (PublicKeyCredentialCreationOptions) |
POST | /webauthn/register | 자격 증명 등록 (AuthenticatorAttestationResponse 검증) |
POST | /webauthn/authenticate/options | 인증 챌린지 생성 (assertionOptionsEndpoint) |
DELETE | /webauthn/register/{id} | 자격 증명 삭제 |
단일 인증 vs MFA 2차 요소
Passkey는 단일 인증과 MFA 2차 요소 인증에서 완전히 다른 URL, 어댑터 및 상태 관리를 사용합니다.
| 측면 | 단일 인증 | MFA 2차 요소 |
|---|---|---|
| 인증 URL | /login/webauthn | /login/mfa-webauthn |
| 어댑터 | PasskeyAuthenticationAdapter | MfaPasskeyAuthenticationAdapter |
| 필터 | Spring Security 내장 | MfaPasskeyAuthenticationFilter |
| 상태 관리 | SecurityContextRepository | MFA 상태 머신 |
| DSL 설정 | .passkey() | .mfa(m -> m.passkey()) |
자동 핸들러 선택
인증 방법에 커스텀 핸들러가 지정되지 않으면, 인증 플로우와 상태 유형에 따라 적절한 핸들러가 자동으로 선택됩니다.
성공 / 실패 핸들러 선택 규칙
| 플로우 | 상태 유형 | 성공 핸들러 | 실패 핸들러 |
|---|---|---|---|
| 단일 인증 | Session | Spring Security 기본값 | Spring Security 기본값 |
| 단일 인증 | OAuth2 | OAuth2SingleAuthSuccessHandler | OAuth2SingleAuthFailureHandler |
| MFA 1차 | 모두 | PrimaryAuthenticationSuccessHandler | UnifiedAuthenticationFailureHandler |
| MFA 후속 | 모두 | MfaFactorProcessingSuccessHandler | UnifiedAuthenticationFailureHandler |
SecurityContextRepository 선택 규칙
| 플로우 | 단계 | 리포지토리 |
|---|---|---|
| 단일 인증 | Session | HttpSessionSecurityContextRepository |
| 단일 인증 | OAuth2 | NullSecurityContextRepository |
| MFA | 1차 (최종 아님) | NullSecurityContextRepository |
| MFA | 최종 단계 | 상태 유형에 따라 자동 선택 |
| MFA | 중간 단계 | NullSecurityContextRepository |
커스텀 핸들러 구현에 대해서는 적응형 MFA 문서의 확장 포인트 섹션을 참조하세요.