mirror of
https://github.com/ktds-dg0501/kt-event-marketing-fe.git
synced 2025-12-06 19:26:24 +00:00
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
156 lines
5.1 KiB
Plaintext
156 lines
5.1 KiB
Plaintext
@startuml user-로그아웃
|
|
!theme mono
|
|
|
|
title User Service - 로그아웃 내부 시퀀스 (UFR-USER-040)
|
|
|
|
actor Client
|
|
participant "UserController" as Controller <<API Layer>>
|
|
participant "AuthenticationService" as AuthService <<Business Layer>>
|
|
participant "JwtTokenProvider" as JwtProvider <<Utility>>
|
|
participant "Redis\nCache" as Redis <<E>>
|
|
|
|
note over Controller, Redis
|
|
**UFR-USER-040: 로그아웃**
|
|
- JWT 토큰 검증
|
|
- Redis 세션 삭제
|
|
- 클라이언트 측 토큰 삭제 (프론트엔드 처리)
|
|
end note
|
|
|
|
Client -> Controller: POST /api/users/logout\nAuthorization: Bearer {JWT}
|
|
activate Controller
|
|
|
|
Controller -> Controller: @AuthenticationPrincipal\n(JWT에서 userId 추출)
|
|
|
|
Controller -> Controller: JWT 토큰 추출\n(Authorization 헤더에서)
|
|
|
|
Controller -> AuthService: logout(token, userId)
|
|
activate AuthService
|
|
|
|
== 1단계: JWT 토큰 검증 ==
|
|
|
|
AuthService -> JwtProvider: validateToken(token)
|
|
activate JwtProvider
|
|
JwtProvider -> JwtProvider: JWT 서명 검증\n(만료 시간 확인)
|
|
JwtProvider --> AuthService: boolean (유효 여부)
|
|
deactivate JwtProvider
|
|
|
|
alt JWT 토큰 무효
|
|
AuthService --> Controller: throw InvalidTokenException\n("유효하지 않은 토큰입니다")
|
|
Controller --> Client: 401 Unauthorized\n{"code": "AUTH_002",\n"error": "유효하지 않은 토큰입니다"}
|
|
deactivate AuthService
|
|
deactivate Controller
|
|
|
|
else JWT 토큰 유효
|
|
|
|
== 2단계: Redis 세션 삭제 ==
|
|
|
|
AuthService -> Redis: 세션 삭제\n(캐시키: user:session:{token})
|
|
activate Redis
|
|
Redis --> AuthService: 삭제된 키 개수 (0 또는 1)
|
|
deactivate Redis
|
|
|
|
alt 세션 없음 (이미 로그아웃됨)
|
|
note right of AuthService
|
|
**멱등성 보장**
|
|
- 세션이 없어도 로그아웃 성공으로 처리
|
|
- 중복 로그아웃 요청에 안전
|
|
end note
|
|
else 세션 있음 (정상 로그아웃)
|
|
note right of AuthService
|
|
**세션 삭제 완료**
|
|
- Redis에서 세션 정보 제거
|
|
- JWT 토큰 무효화 (Blacklist 방식)
|
|
end note
|
|
end
|
|
|
|
== 3단계: JWT 토큰 Blacklist 추가 (선택적) ==
|
|
|
|
note right of AuthService
|
|
**JWT Blacklist 전략**
|
|
- 만료되지 않은 JWT 토큰을 강제로 무효화
|
|
- Redis에 토큰을 Blacklist에 추가 (TTL: 남은 만료 시간)
|
|
- API Gateway에서 Blacklist 확인
|
|
|
|
**API Gateway 연계 시나리오**
|
|
1. 로그아웃: AuthService가 Blacklist에 토큰 추가
|
|
2. 후속 API 요청: API Gateway가 Blacklist 확인
|
|
- Redis GET jwt:blacklist:{token}
|
|
- 존재하면: 401 Unauthorized 즉시 반환
|
|
- 존재하지 않으면: 백엔드 서비스로 라우팅
|
|
3. 만료 시간 도달: Redis TTL 만료로 자동 삭제
|
|
end note
|
|
|
|
AuthService -> JwtProvider: getRemainingExpiration(token)
|
|
activate JwtProvider
|
|
JwtProvider -> JwtProvider: JWT Claims에서\nexp(만료 시간) 추출\n(현재 시간과 비교)
|
|
JwtProvider --> AuthService: remainingSeconds
|
|
deactivate JwtProvider
|
|
|
|
alt 남은 만료 시간 > 0
|
|
AuthService -> Redis: 블랙리스트에 토큰 추가\n(캐시키: jwt:blacklist:{token},\n값: "revoked", TTL: 남은초)
|
|
activate Redis
|
|
Redis --> AuthService: Blacklist 추가 완료
|
|
deactivate Redis
|
|
end
|
|
|
|
== 4단계: 로그아웃 이벤트 발행 (선택적) ==
|
|
|
|
note right of AuthService
|
|
**로그아웃 로깅 및 이벤트**
|
|
- 감사 로그 기록: userId, timestamp, IP
|
|
- 이벤트 발행: LOGOUT_SUCCESS
|
|
- 분석 데이터 수집: 세션 지속 시간, 활동 통계
|
|
end note
|
|
|
|
AuthService -> AuthService: 로그아웃 성공 로그 기록\n(userId, timestamp, sessionDuration)
|
|
|
|
AuthService ->> AuthService: publishEvent(LOGOUT_SUCCESS)
|
|
note right of AuthService
|
|
**이벤트 활용**
|
|
- 비동기 이벤트 처리
|
|
- 분석 시스템 연동
|
|
- 감사 로그 저장소 전송
|
|
end note
|
|
|
|
== 5단계: 응답 반환 ==
|
|
|
|
AuthService --> Controller: LogoutResponse\n(success: true)
|
|
deactivate AuthService
|
|
|
|
Controller --> Client: 200 OK\n{"success": true,\n"message": "안전하게 로그아웃되었습니다"}
|
|
deactivate Controller
|
|
end
|
|
|
|
note over Controller, Redis
|
|
**보안 처리**
|
|
- JWT 토큰 Blacklist: 만료 전 토큰 강제 무효화
|
|
- 멱등성 보장: 중복 로그아웃 요청에 안전
|
|
- 세션 완전 삭제: Redis에서 세션 정보 제거
|
|
- 감사 로그: userId, timestamp, IP, sessionDuration 기록
|
|
|
|
**API Gateway 연계**
|
|
- Blacklist 확인: GET jwt:blacklist:{token}
|
|
- 존재 시: 401 Unauthorized 즉시 반환
|
|
- TTL 자동 관리: 만료 시간 도달 시 자동 삭제
|
|
|
|
**클라이언트 측 처리**
|
|
- 프론트엔드: LocalStorage 또는 Cookie에서 JWT 토큰 삭제
|
|
- 로그인 화면으로 리다이렉트
|
|
- 모든 인증 헤더 제거
|
|
|
|
**성능 목표**
|
|
- Redis 삭제 연산: O(1) 시간 복잡도
|
|
- 평균 응답 시간: 0.1초 이내
|
|
- P95 응답 시간: 0.2초 이내
|
|
|
|
**이벤트 처리**
|
|
- LOGOUT_SUCCESS 이벤트 발행 (비동기)
|
|
- 감사 로그 저장소 전송
|
|
- 분석 데이터 수집
|
|
|
|
**에러 코드**
|
|
- AUTH_002: JWT 토큰 무효
|
|
end note
|
|
|
|
@enduml
|