본문 바로가기
Project/MangoPlate Clone

Jwt 리프레시 토큰을 이용한 액세스 토큰 재발급

by 혀눅짱 2023. 3. 10.

보안상의 이유로 인가에 필요한 액세스 토큰의 만료시간을 매우 짧게 설정하였다.

이제 이토큰이 만료될시 클라이언트측에서 만료되었다는 응답을 받고 토큰재발급 api를 호출한다는 가정하에 로직을 짰다.

@RestController
@RequiredArgsConstructor
public class TokenController {

    private final TokenService tokenService;

    @PostMapping("reIssuanceToken")
    public HashMap<String,String> reIssuanceToken(HttpServletRequest request, HttpServletResponse response){
        HashMap<String,String> result = new HashMap<>();
        String refreshHeader = request.getHeader(JwtTokenInfo.getInfoByKey("refreshHeader"));
        String nwAccessToken = tokenService.ValidRefreshAndReIssuanceAccessToken(refreshHeader);
        if(StringUtils.hasLength(nwAccessToken)){
            result.put("status","success");
            response.addHeader(JwtTokenInfo.getInfoByKey("header"),JwtTokenInfo.getInfoByKey("prefix") + nwAccessToken);
        }else{
            result.put("status","fail");
        }
        return result;

    }
}

 

이 url로 클라이언트가 재발급 요청을 하게된다. 만약 클라이언트 측에서 리프레시 토큰을 넘겨주지 않는다면 당연히 검증할 토큰이 없기때문에 fail로 리턴된다.

 

 

public String ValidRefreshAndReIssuanceAccessToken(String refreshHeader){
    String accessToken = "";
    if(refreshHeader == null || !refreshHeader.startsWith(JwtTokenInfo.getInfoByKey("prefix"))){
        return accessToken;
    }
    try{
        String reFreshToken = refreshHeader.replace(JwtTokenInfo.getInfoByKey("prefix"),"");
        Long id = JWT.require(Algorithm.HMAC512(JwtTokenInfo.getInfoByKey("secret"))).build().verify(reFreshToken).getClaim("id").asLong();
        String email = JWT.require(Algorithm.HMAC512(JwtTokenInfo.getInfoByKey("secret"))).build().verify(reFreshToken).getClaim("email").asString();
        Date accessTokenExpireDt = new Date(System.currentTimeMillis() + 60000);
        if(id != null && StringUtils.hasLength(email)){
            RefreshToken tokenInfo = tokenRepository.findByUserId(id);
            if(reFreshToken.equals(tokenInfo.getTokenName())){
                accessToken = JwtTokenProvider.createAccessToken(id,email,accessTokenExpireDt);
            }
        }
    } catch (SignatureVerificationException | SignatureGenerationException e) {
        log.info("잘못된 JWT 서명입니다.");
    } catch (TokenExpiredException e) {
        log.info("만료된 JWT 토큰입니다.");
    } catch (IllegalArgumentException | JWTVerificationException e) {
        log.info("JWT 토큰이 잘못되었습니다.");
    } catch (Exception e){
        log.info(e.getMessage());
    }

    return accessToken;
}

 

클라이언트로 부터 넘겨받은 토큰정보를 먼저 서명 검증하는데 만약 리프레시 토큰정보 자체가 만료되었거나 잘못된 토큰이면 그냥 리턴해서 fail처리 해버린다. 이경우는 클라이언트에서 다시 로그인하여 액세스토큰과 리프레시 토큰을 새로 발급받아야한다.

 

검증이 완료되었다면  사용자 일련번호로 디비에서 조회하여 넘겨받은 토큰과 디비에 저장된 토큰이 같은지 비교하게된다.

 

모든 절차가 완료되면 새로운 액세스 토큰을 발급하여 클라이언트에게 응답 값 success와 함께 헤더에 토큰정보를 담아 전송한다.

 

일단 대충 인증,인가, 재발급 로직은 완성을 시켜두었는데 클라이언트 측에서 테스트 후 수정이 필요하다면 수정해야될 것 같다.

 

문제는 이제 로그아웃이다. 임의로 토큰을 서버에서 삭제 할 수가없어서 고민을 많이 해보아야 할 것 같다. 일단  redis도 안쓰고 디비로 그냥 할거여서.. 난관이다. 이상 끝.

'Project > MangoPlate Clone' 카테고리의 다른 글

마이페이지 및 위시리스트  (0) 2023.03.29
Jwt 토큰 예외처리  (0) 2023.03.09
Jwt 기본 세팅  (0) 2023.03.03
SpringSecurity 및 jwt 설정 1  (0) 2023.02.27
리뷰 및 메뉴 페이징 목록 구현  (1) 2023.02.27