JWT 로그인 흐름을 정리하면서 로그인 성공 시 JWT를 발급한다고 했는데, 그렇다면 JWT는 어디서 만들고, 어떻게 검증할까?
그 역할을 담당하는 것이 바로 JwtUtil 클래스이다.
JwtUtil : JWT를 생성, 검증, 파싱하는 유틸 클래스
Util : 특정 기능을 모아둔 도구 클래스
JWT 인증 방식에서는 매 요청마다 아래 작업이 반복된다.
• 로그인 시 → JWT 생성
• 요청 시 → JWT 검증
• 토큰에서 → 사용자 정보 추출
이러한 JWT 관련 로직을 한 곳에 모아둔 것이 JwtUtil이다.
SecretKey 생성
private SecretKey secretKey;
public JwtUtil(@Value("${spring.jwt.secret}") String secret){
secretKey = new SecretKeySpec(
secret.getBytes(StandardCharsets.UTF_8),
Jwts.SIG.HS256.key().build().getAlgorithm()
);
}
JWT 서명에 사용할 비밀키를 생성한다.
여기서 @Value("${spring.jwt.secret}")는 application.properties에 정의된 값을 가져오는 역할을 한다.
이렇게 외부 설정을 사용하는 이유는 비밀키를 코드에 직접 작성하지 않고 관리하기 위함이다.
JWT는 그냥 문자열이 아닌 서명된 토큰이다.이때 서명을 생성하고 검증하는 데 사용하는 것이 바로 secretKey이다.
secretKey = 서버만 알고 있는 비밀번호
토큰을 만들때 이 키로 서명하고, 토큰을 검증할 때 이 키로 위조 여부를 확인한다.
따라서 외부에 노출되면 안되는 중요한 값이다.
JWT 생성
public String createJwt(String username, String role, Long expiredMs) {
return Jwts.builder()
.claim("userId",userId)
.claim("role", role)
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + expiredMs))
.signWith(secretKey)
.compact();
}
username + role -> JWT 문자열 생성
.claim() : JWT 안에 사용자 정보를 넣는다..issuedAt : 언제 발급됐는지 기록한다..expiration() : 토큰 유효기간을 설정한다..signWith() : 위에서 만든 비밀키로 서명해 토큰 위조를 방지한다.compact() : JWT 문자열로 반환한다.즉, 사용자 정보를 담은 서명된 토큰을 만드는 과정이다.
JWT는 단순 문자열이 아니라 서명된 데이터이다.
따라서 signWith(secretKey)를 통해 위조가 불가능하도록 만든다.
JWT 검증 및 정보 추출
JwtUtil에는 토큰을 검증하고, 내부 정보를 꺼내는 메서드들이 존재한다.
public String getUsername(String token)
public String getRole(String token)
public Boolean isExpired(String token)
이 메시드들은 각각 다른 값을 반환하지만, 내부적으로 동일한 로직을 사용한다.
Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(token)
즉, 이 토큰이 진짜인지 확인한 후, 안에 있는 데이터를 꺼낸다.
JWT 사용
JwtUtil은 실제로 아래 위치에서 사용한다.
[로그인]
LoginFilter
→ JWT 생성 (createJwt)
[요청]
JwtFilter
→ JWT 검증 (isExpired)
→ 사용자 정보 추출 (getUsername, getRole)