본문 바로가기

Language/Spring

[JWT] Refresh Token을 이용한 Access Token 재발급

Refresh Token을 이용한 Access Token 재발급 로직

@Override
public GatewayFilter apply(Config config) {
    return ((exchange, chain) -> {
        // 생략

        String token = jwtUtil.substringToken(authorization);
        log.info("authorization = {}", authorization);

        try {
            jwtUtil.validateToken(token);
            return chain.filter(exchange);
        } catch (SecurityException | MalformedJwtException | SignatureException e) {
            return onError(exchange, "유효하지 않는 JWT 서명 입니다.", HttpStatus.UNAUTHORIZED);
        } catch (ExpiredJwtException e) {
            log.info("Access Token 만료");
            Claims claims = e.getClaims();

            log.info("Redis에 저장된 RefreshToken 추출");
            String refreshToken = redisService.getRefreshToken(claims.getSubject());

            if(refreshToken != null && jwtUtil.validateToken(refreshToken)){
                log.info("유효한 Refresh Token으로 Access Token 재발급");
                String newAccessToken = jwtUtil.createAccessToken(claims);
                jwtUtil.addJwtToHeader(newAccessToken, exchange.getResponse());
                return chain.filter(exchange);
            } else{
                log.info("유효하지 않은 Refresh Token(기간 만료 or Refresh Token 존재하지 않음)");
                return onError(exchange, "로그인 후 이용 가능합니다.", HttpStatus.UNAUTHORIZED);
            }
        } catch (UnsupportedJwtException e) {
            return onError(exchange, "지원되지 않는 JWT 토큰 입니다.", HttpStatus.UNAUTHORIZED);
        } catch (IllegalArgumentException e) {
            return onError(exchange, "잘못된 JWT 토큰 입니다.", HttpStatus.UNAUTHORIZED);
        }
    });
}
  • jwtUtil.validateToken() 메서드를 사용하여 토큰 검증
  • Access Token이 만료되었을 경우 catch (ExpiredJwtException e){} 예외 처리 실행
  • ExpriedJwtException에는 만료된 토큰의 claims에 접근 가능
  • Redis에 저장한 키 값으로 Refresh Token 추출
  • Refresh Token이 null이 아니고(Redis에 저장) 유효한 토큰일 경우 새로운 Access Token 발급하여 Response Header에 추가
  • 다음 필터로 진행
  • Redis에 Refresh Token이 없거나 만료된  토큰일 경우 Error 메세지 및 상태 응답

Postman을 이용한 테스트

시나리오
  • Access Token 만료 시간 : 25초
  • Refresh Token 만료 시간 : 60초
jwt:
  token:
    access-expiration : 250000 # 25초
    refresh-expiration : 60000 # 1분
  1. 기존 액세스 토큰으로 게임 전체 리스트 조회 → 실패 : 로그인 후 사용 가능
  2. 로그인 → 성공
  3. 게임리스트 조회 →  성공
  4. 25초 뒤 게임리스트 조회 →  성공 : Access Token 재발급
  5. 35초 뒤 다시 로그인(1분) → 실패 : 로그인 후 사용 가능
기존 액세스 토큰으로 게임 전체 리스트 조회 → 실패 : 로그인 후 사용 가능


로그인 → 성공

 

게임리스트 조회 →  성공

25초 뒤 게임리스트 조회 →  성공 : Access Token 재발급

35초 뒤 다시 로그인(1분) → 실패 : 로그인 후 사용 가능