Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static AuthPrinciple from(project.flipnote.auth.entity.UserAuth account)
}

public static AuthPrinciple from(Claims claims) {
long authId = Long.parseLong(claims.getId());
long authId = claims.get(JwtConstants.AUTH_ID, Long.class);
long userId = claims.get(JwtConstants.USER_ID, Long.class);
AccountRole userRole = AccountRole.from(
claims.get(JwtConstants.ROLE, String.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import project.flipnote.auth.entity.UserAuth;
import project.flipnote.auth.model.TokenPair;
import project.flipnote.auth.service.TokenVersionService;
import project.flipnote.common.security.dto.AuthPrinciple;
import project.flipnote.common.security.exception.CustomSecurityException;
import project.flipnote.common.security.exception.SecurityErrorCode;

@Slf4j
@RequiredArgsConstructor
@Component
public class JwtComponent {

private final JwtProperties jwtProperties;
private final TokenVersionService tokenVersionService;
private final TokenIdGenerator tokenIdGenerator;

private SecretKey secretKey;

@PostConstruct
Expand Down Expand Up @@ -63,7 +67,8 @@ private String generateToken(AuthPrinciple userAuth, Date expiration) {

return Jwts.builder()
.subject(userAuth.email())
.id(String.valueOf(userAuth.authId()))
.id(tokenIdGenerator.generate())
.claim(JwtConstants.AUTH_ID, userAuth.authId())
.claim(JwtConstants.USER_ID, userAuth.userId())
Comment on lines +70 to 72
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

jti 무작위화 + AUTH_ID 클레임 분리 — 동시요청 동일 토큰 문제 해결

.id(tokenIdGenerator.generate())로 jti를 무작위화하고, AUTH_ID를 별도 클레임으로 추가한 점 적절합니다. 동일 초 단위 중복 발급 이슈를 제거합니다.

운영 호환성 확인(구토큰 유효기간 동안):


🏁 Script executed:

#!/bin/bash
# AUTH_ID 미포함 토큰이 아직 유통 중인지, 토큰 만료 정책/그레이스 기간 문서 확인 필요
# 코드 기준 검증: AUTH_ID 사용처
rg -nP --type=java 'JwtConstants\.AUTH_ID|claims\.get\(JwtConstants\.AUTH_ID'

Length of output: 257


jti 무작위화 + AUTH_ID 클레임 분리 — 구 토큰 호환성(필수 확인/수정)

.id(tokenIdGenerator.generate())와 AUTH_ID 추가는 적절함. 그러나 AuthPrinciple에서 AUTH_ID를 primitive long으로 바로 읽고 있어( src/main/java/project/flipnote/common/security/dto/AuthPrinciple.java:32 ) AUTH_ID가 없는 기존 토큰이 유통 중이면 claims.get(...)이 null로 인해 NPE 또는 토큰 파싱 실패가 발생함. 토큰 생성 위치: src/main/java/project/flipnote/common/security/jwt/JwtComponent.java:70-72.

  • 조치: claims.get(...)을 Long으로 받아 null 체크 후 호환(fallback 처리 또는 안전한 거부 로그) 로직 추가하거나, 배포 전 기존 토큰 만료/그레이스 기간을 확인해 단계적 롤아웃 계획 수립.
🤖 Prompt for AI Agents
In src/main/java/project/flipnote/common/security/jwt/JwtComponent.java around
lines 70-72, you added .id(tokenIdGenerator.generate()) and
.claim(JwtConstants.AUTH_ID, userAuth.authId()), but existing tokens may lack
AUTH_ID and AuthPrinciple currently reads it as a primitive long (causing NPE on
missing claim). Fix by changing claim extraction in AuthPrinciple to read
AUTH_ID as a Long (wrapper), null-check it, and implement a safe fallback (e.g.,
use userId or a sentinel value, or reject with a clear logged message) so
parsing won’t NPE; add a warning log when falling back and verify rollout/expiry
plan for old tokens before enforcing non-null AUTH_ID.

.claim(JwtConstants.ROLE, userAuth.role().name())
.claim(JwtConstants.TOKEN_VERSION, userAuth.tokenVersion())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public final class JwtConstants {

public static final String ROLE = "role";
public static final String TOKEN_VERSION = "token_version";
public static final String AUTH_ID = "auth_id";
public static final String USER_ID = "user_id";

public static final String AUTH_HEADER = "Authorization";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package project.flipnote.common.security.jwt;

import java.security.SecureRandom;

import org.springframework.stereotype.Component;

@Component
public class TokenIdGenerator {

private final SecureRandom random = new SecureRandom();

public String generate() {
long value = Math.abs(random.nextLong());
return Long.toString(value);
}
}
Loading