package com.ga.common.auth; import com.ga.common.exception.BizException; import com.ga.common.exception.ErrorCode; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.JwtException; import io.jsonwebtoken.security.Keys; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.List; import java.util.Map; /** * JWT 발급/검증. */ @Slf4j @Component public class JwtTokenProvider { private final SecretKey key; private final long accessExpire; private final long refreshExpire; public JwtTokenProvider( @Value("${ga.jwt.secret}") String secret, @Value("${ga.jwt.access-token-expire:7200000}") long accessExpire, @Value("${ga.jwt.refresh-token-expire:604800000}") long refreshExpire ) { byte[] raw = secret.getBytes(StandardCharsets.UTF_8); // 256비트 미만이면 안전하게 패딩 if (raw.length < 32) { byte[] padded = new byte[32]; System.arraycopy(raw, 0, padded, 0, raw.length); raw = padded; } this.key = Keys.hmacShaKeyFor(raw); this.accessExpire = accessExpire; this.refreshExpire = refreshExpire; } public String createAccessToken(Long userId, String loginId, List roles) { return create(userId, loginId, roles, accessExpire, "ACCESS"); } public String createRefreshToken(Long userId, String loginId) { return create(userId, loginId, List.of(), refreshExpire, "REFRESH"); } private String create(Long userId, String loginId, List roles, long expireMs, String type) { Date now = new Date(); return Jwts.builder() .subject(loginId) .claims(Map.of( "uid", userId, "roles", roles, "type", type )) .issuedAt(now) .expiration(new Date(now.getTime() + expireMs)) .signWith(key) .compact(); } public Claims parse(String token) { try { return Jwts.parser().verifyWith(key).build() .parseSignedClaims(token).getPayload(); } catch (ExpiredJwtException e) { throw new BizException(ErrorCode.TOKEN_EXPIRED); } catch (JwtException | IllegalArgumentException e) { throw new BizException(ErrorCode.TOKEN_INVALID); } } public boolean isValid(String token) { try { parse(token); return true; } catch (Exception e) { return false; } } public long getAccessExpire() { return accessExpire; } public long getRefreshExpire() { return refreshExpire; } }