[JWT+] refresh rotate

원모어깨찰빵·2024년 3월 27일
0

스프링

목록 보기
16/17

Refresh Token Rotate란?

유효한 Refresh Token을 받으면 새로운 Access Token만 생성해 주는 것이 아닌 새로운 Refresh Token도 발급하여 로그인 유지 기간을 연장하는 작업

ReissueService 코드 수정

기존의 Access토큰만 발급해주는 코드

//make new JWT
        String newAccess = jwtUtil.createJwt("access", username, role, 600000L);
        //response
        response.setHeader("access", newAccess);

RefreshToken까지 새로 발급해주는 코드

//make new JWT
    String newAccess = jwtUtil.createJwt("access", username, role, 600000L);
    String newRefresh = jwtUtil.createJwt("refresh", username, role, 86400000L);
    //response
    response.setHeader("access", newAccess);
    response.addCookie(createCookie("refresh", newRefresh));

이제 이전에 발급되었던 RefreshToken을 사용하지 못하게 하기 위하여 블랙리스트 작업이 필요하다.
따라서 Refresh토큰을 관리하기 위한 레포지토리와 엔티티 등이 필요하다.

Refresh토큰의 서버차원 관리

Refresh 엔티티

public class Refresh {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;  //어떤 유저의 토큰인지 구분자
    private String refresh;  //토큰
    private String expiration;  //만료시간
}

Refresh 레포지토리

public interface RefreshRepository extends JpaRepository<RefreshEntity, Long> {
    Boolean existsByRefresh(String refresh);
    @Transactional
    void deleteByRefresh(String refresh);
}

로그인 성공 핸들러 수정

refresh객체 만들고 레포에 저장하는 메소드 추가

private void addRefreshEntity(String username, String refresh, Long expiredMs) {
        //refresh객체를 만들고 레포에 저장
        Date date = new Date(System.currentTimeMillis() + expiredMs);
        Refresh refreshEntity = new Refresh();
        refreshEntity.setUsername(username);
        refreshEntity.setRefresh(refresh);
        refreshEntity.setExpiration(date.toString());
        refreshRepository.save(refreshEntity);
    }

onAuthenticationSuccess메소드에 위에 작성한 메소드 추가

//토큰 생성
        String accessToken = jwtUtil.createJwt("access", username, role, 600000L);  //10분
        String refreshToken = jwtUtil.createJwt("refresh", username, role, 86400000L); //24시간
        //Refresh 토큰 저장
        addRefreshEntity(username, refreshToken, 86400000L);
        //Access토큰은 헤더에, Refresh 토큰은 쿠키에 담아 보내기
        response.setHeader("access", accessToken);
        response.addCookie(createCookie("refresh", refreshToken));
        response.setStatus(HttpStatus.OK.value());  //200으로 프론트에 반환쳐주기

RefreshService 수정

기존의 refresh토큰 삭제 후 DB에 새로 생성한 refresh토큰 저장하는 로직 추가

private void addRefreshEntity(String username, String refresh, Long expiredMs) {  //Refresh객체를 DB에 저장(블랙리스트관리)
        Date date = new Date(System.currentTimeMillis() + expiredMs);
        Refresh refreshEntity = new Refresh();
        refreshEntity.setUsername(username);
        refreshEntity.setRefresh(refresh);
        refreshEntity.setExpiration(date.toString());
        refreshRepository.save(refreshEntity);
    }

기존의 reissue 메소드 수정

//make new JWT
        String newAccess = jwtUtil.createJwt("access", username, role, 600000L);
        String newRefresh = jwtUtil.createJwt("refresh", username, role, 86400000L);
        //Refresh 토큰 저장 DB에 기존의 Refresh 토큰 삭제 후 새 Refresh 토큰 저장
        refreshRepository.deleteByRefresh(refresh);
        addRefreshEntity(username, newRefresh, 86400000L);
        //response
        response.setHeader("access", newAccess);
        response.addCookie(createCookie("refresh", newRefresh));

Reference

개발자 유미 노션
개발자 유미 유튜브

profile
https://fuzzy-hose-356.notion.site/1ee34212ee2d42bdbb3c4a258a672612

0개의 댓글