본문 바로가기

TIL(Today I Learned)

TIL-230901(항해99 실전 프로젝트-행동대장(22))

📝오늘 공부한 것

  • 실전프로젝트 - '행동대장' 로그인 시 refresh token 추가 기능 구현

 

📌 Refresh Token 추가

 처음에 refresh token기능을 구현할 때, 프론트에서 만료된 access token으로 request를 하면 나는 만료된 access token인 것이 확인이 되고 refresh token이 유효한 것도 확인이 되면 새로운 access token을 발급하는 방식을 사용하였다. 뭐가 문젠지는 모르겠지만, 계속 프론트에서 새로 발급받은 access token을 받지 못한다고 하였다. CORS에러가 난것도 아니고, fostman으로 잘 확인이 되어서 뭐가 문젠지를 찾지 못했다. 그래서 프론트분과 다른 기능을 먼저 구현을 끝내고 refresh token을 다시 도전해보기로 하였다.

이번에는 새로 시작하는 마음으로 access token을 재발급하는 api를 따로 만드는 방법으로 구현하기로 하였다.

토큰이 만료되면 refresh token으로 request를 하면 나는 새로운 access token을 response하는 방식이었다.

 

✔ UserController

    //토큰 재발급
    @GetMapping("/login/reissueToken")
    public ResponseEntity<CommonResponse<ReissueTokenResponseDto>> reissueToken(HttpServletRequest request, HttpServletResponse response) {
        CommonResponse<ReissueTokenResponseDto> commonResponse = userService.reissueToken(request, response);
        return new ResponseEntity<>(new CommonResponse<>(commonResponse.getMsg()), HttpStatus.CREATED);
    }

 

✔ UserService

    //토큰 재발행
    public CommonResponse reissueToken(HttpServletRequest request, HttpServletResponse response) {

        String refreshToken = jwtUtil.getJwtFromHeader(request, AUTHORIZATION_REFRESH);

        if (StringUtils.hasText(refreshToken)) {
            if (jwtUtil.validateRefreshToken(refreshToken)) {

                refreshTokenRepository.findByRefreshToken(refreshToken).orElseThrow(
                        ()-> new LoginException(ClientErrorCode.NO_REFRESHTOKEN));

                String nickname = jwtUtil.getUserInfoFromRefreshToken(refreshToken);

                String newAccessToken = jwtUtil.createAccessToken(nickname, UserRoleEnum.USER);

                response.addHeader(JwtUtil.AUTHORIZATION_ACCESS, newAccessToken);
                return new CommonResponse(CREATE_REFRESHTOKEN);
            }
        }
        throw new LoginException(ClientErrorCode.INVALID_REFRESHTOKEN);
    }

 

Access Token & Refresh Token

Access Token은 보안에 취약하다. 그렇다고 해서 access token의 만료시간을 짧게 가져가면 자주 로그인을 해주어야 한다. 그래서 Access Token보다는 만료시간이 긴 Refresh Token을 사용하였다.

유저가 로그인 시 프론트에게 Access Token과 Refresh Token을 발급한다. 그러다 유저의 Access Token이 만료가 되면 refresh token으로 Access Token을 요청한다. 

만약 Refresh Token이 만료된다면 유저는 재로그인을 하여야한다.

 

알게 된 점❗ 

[ JWT(JSON Web Token) ]

JSON 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token

 

장점 :

 - 동시 접속자가 많을 때 서버 측 부하 낮춤

 - Client, Server가 다른 도메인을 사용할 때

 

단점 :

 - 구현의 복잡도 증가

 - JWT에 담는 내용이 커질 수록 네트워크 비용 증가(클라이언트 -> 서버)

 - 기 생성된 JWT를 일부만 만료시킬 방법이 없음

 - Secret Key 유출 시 JWT 조작 가능

 

😥어려웠던 것들

Refresh Token도 Access Token과 마찬가지로 보안에 취약하기 때문에 JWT에 많은 정보를 담지 않는다고 한다. 그런데 우리 프로젝트에서는 유저에 대한 정보를 이메일, 닉네임, 비밀번호, 역할, 카카오아이디가 있다. 그 중 이메일과 카카오아이디가 없는 유저도 존재한다. 그래서 JWT에 넣을 수 있는 정보가 닉네임과 역할뿐이었다. 그런데 refresh token을 만들때도 유저에 대한 정보중에 닉네임과 역할이 필요했다.

1. Access Token과 Refresh Token에 같은 유저정보를 넣기

2. Refresh Token에 적은 정보를 넣고 UserRole이 Admin일 경우 Refresh token을 사용하지 않고 Access Token이 만료될 경우 재로그인하기

중에 선택을 해야했다. 우리 프로젝트에는 Admin이 필요하다고 생각되어서 두번째 방법으로 코드를 구현하였다. 어떠한 방법이 더 좋은 방법인지 알지 못해서 어려웠던 것 같다.

 

개선할 점💪🏻

Refresh Token을 JWT가 아닌 다른 방법으로 할 수 있다는 것을 알았다. 지금은 JWT로 밖에 구현할 수 없지만, 조금 더 공부해봐서 Refresh Token이 탈취되었을 경우 그 즉시 무효화할 수 있는 방법을 알아봐야겠다.

https://hudi.blog/refresh-token/

 

Access Token의 문제점과 Refresh Token

Access Token의 문제점 사용자의 잦은 로그아웃 경험 현재 달록에서는 Refresh Token을 사용중이지 않다. Access Token 만을 사용하여 사용자를 인증한다. 현재 달록의 Access Token 유효 기한은 24시간 즉, 하

hudi.blog