contexa-identity
상태 관리
인증 후 상태 관리 전략입니다. Session(서버 메모리/Redis) 또는 OAuth2(JWT Stateless) 중 선택할 수 있습니다. 각 인증 방식은 서로 다른 상태로 독립적으로 구성할 수 있습니다.
개요
DSL에서 인증 방식 뒤에 .session() 또는 .oauth2()를 호출하여 상태를 구성합니다. AbstractFlowRegistrar.StateSetter는 가장 최근에 추가된 플로우에 상태를 적용합니다.
registry
.form(f -> f.loginPage("/login"))
.session(Customizer.withDefaults()) // form -> Session
.rest(r -> r.loginProcessingUrl("/api/auth"))
.oauth2(Customizer.withDefaults()) // rest -> OAuth2
.mfa(m -> m.primaryAuthentication(...).passkey(...))
.session(Customizer.withDefaults()) // mfa -> Session
.build();
Session vs OAuth2 비교
| 항목 | Session | OAuth2 |
|---|---|---|
| 상태 저장소 | 기본은 서버 메모리이며, 분산 배포에서는 Redis 기반 공유 저장소를 선택적으로 사용할 수 있음 | JWT 토큰 (Stateless) |
| 적합한 용도 | 전통적인 웹 앱, SSR | SPA, API, 마이크로서비스 |
| 확장성 | 기본적으로는 인메모리 세션 상태로 동작하며, 다중 인스턴스 공유가 필요할 때 Redis 연동을 선택할 수 있습니다 | Stateless (수평 확장 용이) |
| 내장 보안 | 세션 고정 공격 보호 (sessionFixation().changeSessionId()) | JWT + OIDC + Zero Trust Filter |
| CSRF | 필수 (쿠키 기반) | 불필요 (토큰 기반) |
| 로그아웃 | 세션 무효화 + 쿠키 삭제 | CompositeLogoutHandler와 DeviceAwareOAuth2AuthorizationService를 통한 인가 정보 무효화 |
Session 기반
.session(Customizer.withDefaults())로 구성합니다. 전통적인 웹 애플리케이션 및 서버 사이드 렌더링에 적합합니다.
자동 적용 항목
sessionFixation().changeSessionId()-- 세션 고정 공격 보호- 로그아웃 시 세션 무효화 + 쿠키 삭제
CompositeLogoutHandler통합 (Strategy 패턴)
rawHttp를 통한 추가 구성
.form(f -> f
.rawHttp(http -> http.sessionManagement(s -> s
.maximumSessions(1)
.maxSessionsPreventsLogin(true)))
)
.session(Customizer.withDefaults())
OAuth2 기반
.oauth2(Customizer.withDefaults())로 구성합니다. SPA, 마이크로서비스, API 서버에 적합합니다.
자동 적용 항목
- Resource Server: JWT 인증 컨버터, 인증 실패/접근 거부 핸들러,
SessionCreationPolicy.STATELESS - Authorization Server:
AuthorizationService,ClientRepository, 토큰 엔드포인트,authenticated_usergrant type, OIDC 지원 - OAuth2 CSRF:
spring.auth.oauth2-csrf설정으로 제어
authenticated_user Grant Type
Identity 인증(Form, REST, MFA)을 완료한 사용자에게 OAuth2 토큰을 발급하는 커스텀 grant type입니다. 전통적인 인증과 OAuth2 토큰 발급을 연결하는 브릿지 역할을 합니다.
authenticated_user Grant Flow
===============================
[Form/REST/MFA Authentication Complete]
|
v
[AuthenticatedUserGrantAuthenticationProvider]
|
+-- Client Verification
+-- User Lookup (UserRepository)
+-- Scope Resolution
+-- Access Token Generation (JWT)
+-- Refresh Token Generation (optional)
+-- Authorization Persistence (transactional)
|
v
[JWT Token Issuance Complete]
설정 속성
AuthContextProperties (spring.auth.*)의 핵심 설정입니다.
핵심 설정 (spring.auth.*)
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
state-type | enum | OAUTH2 | 인증 상태 타입 (OAUTH2, SESSION) |
token-transport-type | enum | HEADER | 토큰 전송 방식 (HEADER, COOKIE, HEADER_COOKIE) |
token-issuer | enum | INTERNAL | 토큰 발급자 (INTERNAL, AUTHORIZATION_SERVER) |
factor-selection-type | enum | SELECT | MFA 인증 요소 선택 전략 |
access-token-validity | long (ms) | 3600000 (1시간) | Access 토큰 유효 기간 |
refresh-token-validity | long (ms) | 604800000 (7일) | Refresh 토큰 유효 기간 |
refresh-rotate-threshold | long (ms) | 43200000 (12시간) | Refresh 토큰 회전 임계값 |
enable-refresh-token | boolean | true | Refresh 토큰 활성화 |
allow-multiple-logins | boolean | false | 동시 다중 로그인 허용 |
max-concurrent-logins | int | 3 | 최대 동시 로그인 수 |
cookie-secure | boolean | true | Cookie Secure 플래그 |
token-persistence | String | "memory" | 생성된 로그인/MFA 페이지와 SDK에 전달되는 기본 토큰 저장 방식 |
token-prefix | String | "Bearer " | 토큰 접두사 |
roles-claim | String | "roles" | JWT roles claim |
scopes-claim | String | "scopes" | JWT scopes claim |
oauth2-csrf | boolean | false | OAuth2 CSRF 보호 |
TokenTransportType 상세
| 값 | accessToken | refreshToken |
|---|---|---|
HEADER | HTTP Header | HTTP Header |
COOKIE | Cookie | Cookie |
HEADER_COOKIE (권장) | HTTP Header | Cookie |
OAuth2 설정 (spring.auth.oauth2.*)
| 속성 | 기본값 | 설명 |
|---|---|---|
client-id | default-client | OAuth2 클라이언트 ID |
client-secret | 173f8245-5f7d-4623-a612-aa0c68f6da4a | 클라이언트 시크릿 |
issuer-uri | http://localhost:9000 | 토큰 발급자 URI |
token-endpoint | /oauth2/token | Authorization Server 토큰 엔드포인트 |
scope | read | 기본 요청 scope |
redirect-uri | http://localhost:8080 | 클라이언트 리다이렉트 URI |
authorized-uri | 미설정 | 선택적 사전 승인 리다이렉트 URI |
jwk-key-store-path | 미설정 | JWK 키스토어 경로 |
jwk-key-store-password | 미설정 | 키스토어 비밀번호 |
jwk-key-alias | 미설정 | 키 별칭 |
jwk-key-password | 미설정 | 키 비밀번호 |
MFA 설정 (spring.auth.mfa.*)
| 속성 | 기본값 | 설명 |
|---|---|---|
session-timeout-ms | 600000 (10분) | MFA 세션 타임아웃 |
challenge-timeout-ms | 300000 (5분) | 챌린지 타임아웃 |
inactivity-timeout | 900000 (15분) | 비활성 MFA 세션 타임아웃 |
cache-ttl | 300000 (5분) | MFA 상태 캐시 TTL |
session-refresh-interval-ms | 30000 (30초) | 활성 MFA 세션 갱신 주기 |
state-machine-timeout-ms | 10000 (10초) | 상태 머신 실행 타임아웃 |
max-retry-attempts | 5 | 최대 재시도 횟수 |
account-lockout-duration-ms | 900000 (15분) | 계정 잠금 기간 |
minimum-delay-ms | 500 | 민감한 MFA 동작 사이의 최소 지연 |
otp-token-validity-seconds | 300 | OTP 유효 기간 (초) |
otp-token-length | 6 | OTP 코드 길이 |
sms-resend-interval-seconds | 60 | SMS 재전송 최소 간격 |
email-resend-interval-seconds | 120 | 이메일 재전송 최소 간격 |
device-remember-duration-ms | 2592000000 (30일) | 기기 신뢰 유지 기간 |
state-machine-pool-size | 100 | 상태 머신 작업 풀 크기 |
state-machine-cache-ttl-ms | 300000 (5분) | 상태 머신 캐시 TTL |
circuit-breaker-failure-threshold | 5 | 서킷 브레이커 실패 임계값 |
circuit-breaker-timeout-seconds | 30 | 서킷 브레이커 타임아웃 |
detailed-logging-enabled | false | 상세 MFA 디버그 로그 활성화 |
metrics-enabled | true | MFA 메트릭 활성화 |
audit-logging-enabled | true | MFA 감사 로그 활성화 |
session-storage-type | http-session | MFA 세션 저장소 기본 유형 |
auto-select-repository | false | 세션 저장소 자동 선택 여부 |
repository-priority | redis,memory,http-session | 저장소 선택 우선순위 |
fallback-repository-type | http-session | 대체 저장소 유형 |
MFA 하위 설정 그룹
| Prefix | 설명 | 대표 기본값 |
|---|---|---|
spring.auth.mfa.http-session.* | HTTP Session 기반 MFA 저장소 설정 | enabled=true, session-attribute-name=MFA_SESSION_ID |
spring.auth.mfa.redis.* | 분산 배포용 Redis 기반 MFA 저장소 설정 | key-prefix=mfa:session:, cookie-name=MFA_SID, same-site=Strict |
spring.auth.mfa.memory.* | 인메모리 MFA 저장소 튜닝 | cleanup-interval-minutes=5, max-sessions=10000 |
spring.auth.mfa.sms-factor.* | SMS 요소 전송 설정 | provider=default, template-id=mfa_sms_template, enabled=true |
spring.auth.mfa.email-factor.* | 이메일 요소 전송 설정 | from-address=noreply@company.com, template-id=mfa_email_template, enabled=true |
application.yml 예제
spring:
auth:
state-type: OAUTH2
token-transport-type: header_cookie
access-token-validity: 3600000
enable-refresh-token: true
oauth2:
client-id: my-client
issuer-uri: https://auth.example.com
jwk-key-store-path: classpath:keystore.jks
mfa:
session-timeout-ms: 600000
otp-token-validity-seconds: 300
session-storage-type: redis
redis:
key-prefix: mfa:session:
cookie-name: MFA_SID