이번 포스팅에서는 유효한 RefreshToken을 활용하여 만료된 AccessToken을 갱신하고 MySQL에 RefreshToken을 저장하는 것이 아닌 Redis에 저장하여 효율적으로 토큰을 관리해보려고 한다. 또한, MySQL에서 refreshToken을 조회했을 때와 Redis를 통해서 refreshToken을 조회했을 때의 성능 차이를 비교해보려고 한다.
MySQL에서 RefreshToken 관리
@Override
public UserDto.UserInfoResponseDTO login(final UserDto.LoginRequestDTO requestDTO) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(requestDTO.getUserId(), requestDTO.getUserPassword());
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
User user = userMapper.findById(requestDTO.getUserId())
.orElseThrow(() -> new RestApiException(CustomResponseCode.USER_NOT_FOUND));
JwtToken jwtToken = jwtTokenProvider.generateToken(authentication);
userMapper.updateRefreshToken(jwtToken.getRefreshToken());
return UserDto.UserInfoResponseDTO.builder()
.userId(user.getUserId())
.userName(user.getUserName())
.joinDate(user.getJoinDate())
.profile(user.getProfile())
.role(user.getRole())
.email(user.getEmail())
.accessToken(jwtToken.getAccessToken())
.refreshToken(jwtToken.getRefreshToken())
.build();
}
사용자는 만료된 AccessToken을 보내면 서버에서는 401에러를 내려줄 것이다. 401 에러를 받은 사용자는 가지고 있는 RefreshToken을 서버로 전송하여 새로운 AccessToken 발급을 요청한다.
regenerateToken() 에서 getAuthentication()을 통해 토큰을 검증하고 generateToken에 사용될 Authentication을 생성한다.
토큰에서 추출한 사용자 ID를 활용하여 Login 할 때 저장한 MySQL에서의 RefreshToken을 조회한다. 사용자가 보낸 RefreshToken과 MySQL에 저장된 값을 비교하여 유효성을 검증하게 된다.
이후, 새로운 토큰을 발급하고 RefreshToken을 MySQL에 update 하여 새로운 값으로 갱신시킨다.
MySQL을 활용하여 RefreshToken을 처리한 결과 55ms의 응답 시간이 걸린 것을 확인할 수 있다. Redis의 경우 16ms의 응답 시간을 나타내며 디스크 기반인 MySQL에서 관리할 때보다 인메모리 방식인 Redis에서 관리할 때 효율적으로 처리할 수 있는 것을 확인할 수 있었다.