코딩과 결혼합니다

231024 - [Game_Crew]JWT 본문

코딩과 매일매일♥/Game_Crew

231024 - [Game_Crew]JWT

코딩러버 2023. 10. 24. 11:14
728x90

JWT을 생성하고 검증하는 클래스

@Slf4j(topic = "JwtUtil")
@Component
public class JwtUtil {
    // Header KEY 값
    public static final String AUTHORIZATION_HEADER = "Authorization";
    // Token 식별자
    public static final String BEARER_PREFIX = "Bearer ";
    // 토큰 만료시간
    private final long TOKEN_TIME = 60 * 60 * 1000L; // 60분

    @Value("${jwt.secret.key}") // Base64 Encode 한 SecretKey
    private String secretKey;
    private Key key;
    private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  • 필드 :
    • AUTHORIZATION_HEADER: JWT를 포함하는 HTTP 요청의 헤더 키를 나타내는 상수
    • BEARER_PREFIX: JWT를 식별하기 위한 접두사를 나타내는 상수
    • TOKEN_TIME: 토큰의 만료 시간을 나타내는 변수로, 60분으로 설정
    • secretKey: Base64로 인코딩된 시크릿 키 값을 저장하는 변수
    • key: secretKey 값을 디코딩하여 Key 객체로 초기화
    • signatureAlgorithm: JWT 서명 알고리즘으로 HS256 (HMAC with SHA-256)을 사용
    @PostConstruct
    public void init() {
        byte[] bytes = Base64.getDecoder().decode(secretKey);
        key = Keys.hmacShaKeyFor(bytes);
    }
  • @PostConstruct 어노테이션이 붙은 메서드로, 객체가 생성된 후에 실행된다. secretKey 값을 Base64 디코딩하여 key 변수에 할당

 

    // 토큰 생성
    public String createToken(String username) {
        Date date = new Date();

        return BEARER_PREFIX +
                Jwts.builder()
                        .setSubject(username) // 사용자 식별자값(ID)
                        .setExpiration(new Date(date.getTime() + TOKEN_TIME)) // 만료 시간
                        .setIssuedAt(date) // 발급일
                        .signWith(key, signatureAlgorithm) // 암호화 알고리즘
                        .compact();
    }
  • 사용자 이름(username)을 받아와서 JWT 토큰을 생성한다. 발급일(issuedAt), 만료 시간(expiration), 서명 알고리즘(signatureAlgorithm) 등의 정보를 설정하여 Jwts.builder()를 사용해 토큰을 생성하고, key와 함께 서명

 

    // header 에서 JWT 가져오기
    public String getJwtFromHeader(HttpServletRequest request) {
        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
            return bearerToken.substring(7);
        }
        return null;
    }
  • HttpServletRequest에서 Authorization 헤더에서 JWT 값을 가져온다. "Bearer " 접두사로 시작하는 Authorization 값에서 실제 JWT 부분만 추출하여 반환

 

    // 토큰 검증
    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;
        } catch (SecurityException | MalformedJwtException | SignatureException e) {
            log.error("Invalid JWT signature, 유효하지 않는 JWT 서명 입니다.");
        } catch (ExpiredJwtException e) {
            log.error("Expired JWT token, 만료된 JWT token 입니다.");
        } catch (UnsupportedJwtException e) {
            log.error("Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다.");
        } catch (IllegalArgumentException e) {
            log.error("JWT claims is empty, 잘못된 JWT 토큰 입니다.");
        }
        return false;
    }

    // 토큰에서 사용자 정보 가져오기
    public Claims getUserInfoFromToken(String token) {
        return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
    }
}
  • validateToken(): 주어진 token이 유효한지 검증. Jwts.parserBuilder()와 key를 사용하여 서명이 올바른지, 만료되지 않았는지 등의 검사를 수행하고 예외 처리를 한다.
  • getUserInfoFromToken(): 주어진 token에서 클레임(Claims) 정보(예: 사용자 이름)를 추출하여 반환