[ASSIGNMENT] 7차 과제 구현 - #18
Open
Kimgyuilli wants to merge 9 commits into
Open
Conversation
프리픽스 기반 알고리즘 식별을 도입하여 향후 Argon2id 등으로 점진적 마이그레이션할 수 있는 경로를 확보한다.
RDB 블랙리스트 엔티티와 JPA 레포지토리를 제거하고, per-entry TTL을 토큰 잔여 유효 시간에 정렬하는 Caffeine 캐시로 대체한다. 매 요청 DB 조회를 인메모리 조회로 절감하고, 만료된 항목은 자동 제거된다. 사용자 역할 조회도 Caffeine 캐시(5분 TTL)를 적용하여 DB 부하를 줄인다.
회전된 구 토큰이 재사용되면 사용자의 토큰을 전체 무효화하여 탈취를 감지·차단한다. 회전 직후 10초간 구 토큰을 Grace Period로 허용하여 동시 요청에 의한 정상 사용자 세션 끊김을 방지한다.
9개 의존성을 가진 AuthService를 3개 서비스로 분리한다. - AuthTokenService: 토큰 발급, 회전(Rotation + Grace Period), 회수 - SocialLoginService: OAuth 프로필 검증과 자동 회원가입 - AuthService: 자격증명 검증과 흐름 조율 UserCommandService도 AuthTokenService.revoke()를 사용하도록 전환한다.
Application Service(AuthService)와 Domain Service(AuthTokenService, SocialLoginService)의 계층을 패키지로 명시한다. - domain/service: 토큰 생명주기, 소셜 로그인 도메인 로직 - domain/port: OAuth 클라이언트 포트 인터페이스 - domain/model: AuthTokenResult 값 객체 - application/service: 유스케이스 조율 (AuthService)
Grace Period 경로에서 issueAndSaveTokens를 재호출하면 정상 회전 시 발급된 refresh token이 덮어써져 첫 번째 응답의 토큰이 무효화되는 문제를 수정한다. Grace Period 캐시에 발급 결과를 함께 저장하여 동시 요청 시 동일한 토큰을 반환하도록 변경한다. 사용자 삭제 시 역할 캐시를 즉시 무효화하여, 삭제된 사용자가 캐시 TTL 동안 인증되는 문제를 수정한다. 캐시를 UserRoleCache 컴포넌트로 추출하여 필터와 서비스 양쪽에서 접근할 수 있도록 한다.
- UserRoleCache에서 Caffeine cache.get()이 null 반환 시 NPE를 던지는 버그를 수정한다. getIfPresent + 수동 put으로 전환. - AuthTokenService(domain)이 infrastructure를 직접 참조하던 역방향 의존을 RefreshTokenHashPort, RefreshTokenGracePeriodPort 인터페이스로 추상화하여 제거한다. - AuthErrorCode 선언 순서를 코드 번호순으로 정렬한다. - reissue()의 동시성 제약을 Javadoc에 명시한다.
8개 파일이 혼재된 infrastructure 패키지를 정리한다. - persistence: JPA 레포지토리와 어댑터 - cache: Caffeine 기반 블랙리스트·Grace Period 구현체 - oauth: Google OAuth 클라이언트 - security: Refresh Token HMAC 해셔
Kimgyuilli
requested review from
1siis1,
beneruufin,
jaehunshin-git and
khj011219
May 24, 2026 15:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔥Pull requests
close #16
👷 과제 구현
아티클 기반 개선
DelegatingPasswordEncoder전환 (알고리즘 회전 지원)구현한 내용에 대해서 설명해주세요
DelegatingPasswordEncoder 전환
BCryptPasswordEncoder를PasswordEncoderFactories.createDelegatingPasswordEncoder()로 교체했습니다.{bcrypt}프리픽스가 붙어 알고리즘을 식별하고, 향후 Argon2id 같은 알고리즘으로 점진적 마이그레이션이 가능해집니다.DelegatingPasswordEncoder로 적용한 형태입니다.Access Token 블랙리스트 Caffeine 전환
Expiry)을 토큰의 잔여 유효 시간에 정렬하여, 토큰이 자연 만료되는 시점에 블랙리스트 항목도 함께 제거되도록 했습니다.Refresh Token Reuse Detection + Grace Period
ConcurrentHashMap.remove()의 원자성으로 이중 발급을 막습니다.사용자 역할 Caffeine 캐싱
JwtAuthenticationFilter에서 매 요청마다 수행하던userRepository.findById()DB 조회를 Caffeine 캐시(5분 TTL, max 10K)로 절감했습니다.evictUserRole()메서드로 사용자 삭제나 역할 변경 시 캐시를 즉시 무효화할 수 있습니다.cache.get(userId, this::loadUserRole)을 사용해 같은 사용자 ID에 대한 동시 캐시 미스가 발생해도 로딩 함수가 중복 실행되지 않도록 했습니다.Optional<UserRole>을 캐시 값으로 사용했습니다.AuthService 책임 분리
AuthService는 9개 의존성을 가지고 자격증명 검증, 소셜 로그인, 토큰 생명주기를 모두 담당하고 있었습니다.AuthTokenService(Domain Service)로, 소셜 로그인을SocialLoginService(Domain Service)로 추출했습니다.AuthService는 자격증명 검증과 흐름 조율만 담당하는 Application Service(Use Case)로 남겼습니다.회원 탈퇴 인증 세션 회수 포트 분리
UserCommandService가AuthTokenService와UserRoleCache를 직접 의존하지 않도록AuthSessionPort를 추가했습니다.authSessionPort.revoke(authenticatedUser)만 호출하고, 실제 refresh token 삭제, access token 블랙리스트 등록, 역할 캐시 무효화는AuthSessionPortAdapter가 처리합니다.고민했던 포인트
Redis vs Caffeine
Service 계층 분리
presentation → application → domain ← infrastructure로 명확하게 배치했습니다.OAuthProviderClient)도application.client에서domain.port로 옮겨 domain service가 application을 역참조하지 않도록 정리했습니다.