Repository navigation
feat: 재발급 토큰 엔티티 RefreshToken 추가 (#32) - #57
Conversation
chjpooh2002
left a comment
There was a problem hiding this comment.
이미 머지되긴 했는데 findByTokenHash에 남긴 코멘트는 한 번 확인 부탁드립니다!
|
|
||
| public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> { | ||
|
|
||
| Optional<RefreshToken> findByTokenHash(String tokenHash); |
There was a problem hiding this comment.
재발급 서비스에서 이 메서드로 토큰을 찾고 revoke()로 폐기한 뒤 새 토큰을 저장하는 흐름이 될 것 같은데, 같은 토큰으로 요청 두 개가 동시에 오면 둘 다 "폐기 안 됨"을 읽어서 둘 다 새 토큰을 받게 됩니다. 탈취된 토큰을 공격자와 사용자가 거의 동시에 쓰면 재사용 감지가 안 걸리는 거라, 계보 폐기 설계가 막으려는 상황이 그대로 뚫립니다.
둘 중 하나로 막으면 될 것 같습니다!
- 이 조회에
@Lock(LockModeType.PESSIMISTIC_WRITE)를 붙인 재발급 전용 조회를 따로 두기 update RefreshToken t set t.revokedAt = :now where t.id = :id and t.revokedAt is null조건부 갱신을 두고, 반영 건수가 0이면 재사용으로 처리
이번 PR에 같이 넣어도 되고, 재발급 PR에서 넣어도 괜찮습니다. 어느 쪽으로 할지만 정해 주세요!
| * 계보 전체를 폐기한다 (이미 쓴 토큰의 재사용 감지). 이미 폐기된 토큰은 처음 폐기 시각을 그대로 둔다. | ||
| * refresh_tokens에는 updated_at이 없어 직접 넣을 시각 컬럼이 따로 없다. | ||
| */ | ||
| @Modifying(flushAutomatically = true, clearAutomatically = true) |
There was a problem hiding this comment.
clearAutomatically = true라서 이 메서드를 부른 뒤에는 같은 트랜잭션에서 미리 읽어 둔 RefreshToken이 영속 상태에서 빠지는 점만 재발급 서비스 만들 때 참고해 주세요. 계보 폐기 후 그 엔티티를 고쳐도 반영이 안 됩니다. (설정 자체는 맞다고 생각해요!)
| } | ||
|
|
||
| /** 만료 시각과 같으면 만료다. */ | ||
| public boolean isExpired(LocalDateTime now) { |
There was a problem hiding this comment.
사소한 건데, revoke()는 시각이 null이면 규칙 위반으로 막는데 isExpired()는 검사 없이 바로 NullPointerException이 나요. 맞춰 두면 실수했을 때 메시지가 더 분명할 것 같습니다! 수정은 선택사항입니다!
|
|
||
| private static final String HASH = RefreshTokenFixture.hash(1); | ||
| private static final String FAMILY_ID = RefreshTokenFixture.FAMILY_ID; | ||
| private static final LocalDateTime EXPIRES_AT = LocalDateTime.of(2026, 11, 8, 10, 0); |
There was a problem hiding this comment.
픽스처에 같은 값(RefreshTokenFixture.EXPIRES_AT)이 있어서 그걸 쓰면 될 것 같아요. 바로 위 HASH, FAMILY_ID처럼요! 선택사항입니다~
관련 이슈
작업 내용
RefreshToken엔티티·ClientType(WEB/EXTENSION)·레포지토리 (ERD 3-3)family_id로 묶음revoke(처음 폐기 시각 유지),isExpired(만료 시각과 같으면 만료)revokeFamily(재사용 감지 시 계보 폐기),revokeAllByUserId(로그아웃 시 웹·확장 모두 폐기): 이미 폐기된 토큰은 건드리지 않음명세와 달라진 점
없음
테스트
10개, 전체
./gradlew build통과확인 체크리스트
./gradlew build통과global공통 코드를 바꿨다면 디스코드에 공유함 (해당 없음)