accessToken과 refreshToken 사용하여 로그인하기

썸머·2023년 4월 12일

1. 기존방식

  • 기존 코드는 refreshToken의 존재여부와 유효성을 확인하여 accessToken을 발급하였다. 그러나 이는 refreshToken이 유효하다는 것만 보장하고, 악성 사용자가 유효한 refreshToken을 가지고 있다면 새로운 액세스 토큰을 발급받을 수 있게 된다. 따라서 Redis 내에 있는 refreshToken과 비교하는 방식으로 바꾸고자 한다.
  • 왜 redis 또는 db 내에 refreshToken이 저장되어있어야 할까?
    • 특정 계정에서 이상 행동이 발생한 경우, refreshToken을 삭제하거나 무효화하기 위해 통제권을 가지고있어야 한다. 예를 들어, 계정이 해킹되거나 무단 액세스가 발생한 경우, 사용자의 refreshToken을 무력화시켜 해당 계정에 대한 추가적인 액세스를 방지할 수 있다.

2. 수정코드

UserService

//로그인
    public TokenInfo login(Login login){
        //사용자 인증
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(login.getId(), login.getPassword());
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

        //토큰 생성
        TokenInfo tokenInfo = jwtTokenProvider.createAllToken(authentication);

        //리프레시 토큰 redis에 저장(expirationTime 설정을 통해 자동 삭제 처리)
        redisTemplate.opsForValue().set("RT:"+authentication.getName(),
                tokenInfo.getRefreshToken(), tokenInfo.getRefreshTokenExpirationTime(), TimeUnit.MICROSECONDS);
        return tokenInfo;
    }
  • 로그인 시 refreshToken을 redis에 저장한다.

UserService

//토큰 재발급을 위한 reissue()
public TokenInfo reissue(Reissue reissue){
    // refresh token 검증
    if(!jwtTokenProvider.validateToken(reissue.getRefreshToken())){
        throw new IllegalArgumentException("Refresh Token 정보가 유효하지 않습니다.");
    }

    // Access Token 에서 User email 를 가져옴
    Authentication authentication = jwtTokenProvider.getAuthentication(reissue.getAccessToken());

    // Redis 에서 User email 을 기반으로 저장된 Refresh Token 값을 가져옴
    String refreshToken = (String) redisTemplate.opsForValue().get("RT:"+authentication.getName());

    if(!refreshToken.equals(reissue.getRefreshToken())){
        throw new IllegalStateException("Refresh Token 정보가 일치하지 않습니다");
    }
    // 새로운 토큰 생성
    TokenInfo tokenInfo = jwtTokenProvider.createAllToken(authentication);

    // RefreshToken Redis 업데이트
    redisTemplate.opsForValue().set("RT:" + authentication.getName(), tokenInfo.getRefreshToken(),
                    tokenInfo.getRefreshTokenExpirationTime(), TimeUnit.MILLISECONDS);

    return tokenInfo;
}
  1. AT을 재발급 받기위해 refreshToken을 검증한다.
  2. Redis에서 email로 RT값을 받아온다.
  3. 넘어온 RT값과 redis에서 email로 가져온 RT값을 비교한다.
  4. 같으면 새로운 토큰을 생성하고 redis를 업데이트 한다.
profile
썸머의 개발블로그

0개의 댓글