Spring Boot 프로젝트에서 JWT(Json Web Token)를 이용한 인증 시스템을 구현하는 방법에 대해 알아보겠습니다. 특히 이번 포스트에서는 JWT 토큰 생성과 검증을 담당하는 Provider 클래스 구현에 초점을 맞추어 설명하겠습니다.
JWT는 JSON Web Token의 약자로, 당사자 간에 정보를 JSON 객체로 안전하게 전송하기 위한 독립적인 방법을 정의하는 개방형 표준(RFC 7519)입니다. 이 정보는 디지털 서명이 되어 있으므로 신뢰할 수 있습니다.
먼저 build.gradle에 필요한 의존성을 추가합니다.
dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
}
JWT 토큰의 생성과 검증을 담당하는 Provider 클래스를 구현합니다.
@Slf4j
@Component
public class JwtTokenProvider {
private Key key;
@Value("${jwt.token-validity-in-milliseconds}")
private long tokenValidityInMilliseconds;
@PostConstruct
protected void init() {
// HS512 알고리즘용 키 자동 생성
this.key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
log.info("JWT secret key successfully generated for HS512");
}
Access Token과 Refresh Token을 생성하는 메서드를 구현합니다.
public String createAccessToken(String id, Long memberNo, String name, MemberRole role) {
return createToken(id, memberNo, name, role, tokenValidityInMilliseconds);
}
public String createRefreshToken(String id, Long memberNo, String name, MemberRole role) {
return createToken(id, memberNo, name, role, tokenValidityInMilliseconds * 2);
}
private String createToken(String id, Long memberNo, String name, MemberRole role, long validityInMilliseconds) {
Claims claims = Jwts.claims().setSubject(id);
claims.put("memberNo", memberNo);
claims.put("name", name);
claims.put("role", role.name());
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(validity)
.signWith(key, SignatureAlgorithm.HS512)
.compact();
}
토큰의 유효성을 검증하고 필요한 정보를 추출하는 메서드들을 구현합니다.
public boolean validateToken(String token) {
try {
Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token);
return true;
} catch (SecurityException | MalformedJwtException e) {
log.warn("잘못된 JWT 서명입니다.");
} catch (ExpiredJwtException e) {
log.warn("만료된 JWT 토큰입니다.");
} catch (UnsupportedJwtException e) {
log.warn("지원되지 않는 JWT 토큰입니다.");
} catch (IllegalArgumentException e) {
log.warn("JWT 토큰이 잘못되었습니다.");
}
return false;
}
public String getIdFromToken(String token) {
try {
return parseClaims(token).getSubject();
} catch (ExpiredJwtException e) {
return e.getClaims().getSubject();
}
}
jwt:
token-validity-in-milliseconds: 3600000 # 1시간