📘 JWT 사용하여 토큰 재발급 기능 구현
JWT 활용한 로그인/로그아웃
Access Token은 탈취되었을 때 보안에 취약할 수 있기 때문에, 일반적으로 유효시간이 짧게 설정. (보통 약 15분)Access Token이 만료되면, 클라이언트는 서버에 Refresh Token을 사용하여 새로운 Access Token 을 요청Access Token 발급 후 반환 후, 프론트가 새 토큰으로 다시 원래 API 요청 시도POST /api/reissue
Authorization: Bearer {RefreshToken}
//토큰 재발급
public AccessTokenDto reissueAccessToken(String refreshToken) {
//Refresh 토큰으로 userId 생성
Long userId = tokenService.getUserIdFromRefreshToken(refreshToken);
if(userId == null) return null;
//발급 받은 토큰 리턴
String newAccessToken = tokenService.reissueAccessToken(userId);
return new AccessTokenDto(newAccessToken);
}
public Long getUserIdFromRefreshToken(String refreshToken){
//DB 에 저장된 토큰과 일치하는지 확인 -> 없으면 예외
Optional<Token> token = tokenRepository.findByRefreshToken(refreshToken);
if(token.isEmpty()) return null;
return jwtTokenProvider.extractUserId(refreshToken);
}
Refresh 토큰이 DB 와 일치하지 않으면 해당 토큰은 비정상적인 토큰으로 판단되게 때문에 Null 을 리턴해준다.@PostMapping("/reissue")
public ResponseEntity<AccessTokenDto> reissue(HttpServletRequest request,
HttpServletResponse response) {
//쿠키에서 refresh token 꺼내기
String refreshToken = tokenExtractor.extractRefreshTokenFromCookie(request)
.orElseThrow(()-> new CustomException(ErrorCode.REQUIRED_LOGIN));
AccessTokenDto newAccessToken = authService.reissueAccessToken(refreshToken);
//DB 에서 refresh 토큰 불일치시 비정상적인 접근으로 판단 refresh 토큰 쿠키에서 리셋
if(newAccessToken == null) {
tokenCookieUtils.deleteRefreshTokenCookie(response);
throw new CustomException(ErrorCode.INVALID_ACCESS);
}
return new ResponseEntity<>(newAccessToken, HttpStatus.OK);
}
//클라이언트 쿠키에서 삭제 (MaxAge = 0)
public void deleteRefreshTokenCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("refresh_token", null);
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setMaxAge(0);
response.addCookie(cookie);
}
Refresh 토큰 이 없다면 예외처리Null 처리가 되면 Refresh 토큰을 비정상 적이라고 판단하여 쿠키의 Refresh 토큰을 리셋해주고 예외처리를 해준다.
200 OK 와 함께 Access 토큰이 Body 로 반환된다.