반응형

JWT 토큰 설정을 먼저 보고싶으시다면 하단의 포스트를 참고 하세용!

https://goorme-green.tistory.com/22

 

JWT 인증 적용

backoffice 프로젝트를 하던 도중 팀장님의 한마디... "세션 인증 걷어 내고 JWT 적용해볼까??" 사실 여기에 대한 내 생각은 로드밸런서도 없고 backoffice 서비스의 특성상 사용자가 많지도 않구... 도메

goorme-green.tistory.com

 

1. JWT 와 Cookie 를 이용한 로그인 방식

@Component
public class CookieUtil {

    public void deleteCookie(HttpServletResponse response){
        Cookie accessTokenCookie = new Cookie("accessToken", null); // 값은 null 또는 "" 사용
        Cookie refreshTokenCookie = new Cookie("refreshToken", null);
        accessTokenCookie.setMaxAge(0); // 즉시 만료
        refreshTokenCookie.setMaxAge(0);
        accessTokenCookie.setPath("/");
        refreshTokenCookie.setPath("/");
        response.addCookie(accessTokenCookie);
        response.addCookie(refreshTokenCookie);
    }

    public void updateCookie(HttpServletResponse response, SignInResponse signInResponse) {
        Cookie accessTokenCookie = new Cookie("accessToken", signInResponse.getAccessToken());
        Cookie refreshTokenCookie = new Cookie("refreshToken", signInResponse.getRefreshToken());
        refreshTokenCookie.setMaxAge(60*60*24);
        accessTokenCookie.setPath("/");
        refreshTokenCookie.setPath("/");
        response.addCookie(accessTokenCookie);
        response.addCookie(refreshTokenCookie);
    }

    public String getAccessToken(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            return null;
        }
        for (Cookie cookie : cookies) {
            if ("accessToken".equals(cookie.getName())) {
                return cookie.getValue();
            }
        }
        return null;
    }
}

 

구현 방법 및 로직
1) 토큰의 발급 및 저장:
사용자 로그인 후, 서버는 JWT를 생성하고 access Token과 refresh Tokne을 모두 쿠키에 저장한다.
2) 인증 과정:
클라이언트는 Access Token이 key인 쿠키값을 가져와 Authorization 헤더에 넣어 API를 호출한다.
3) 토큰의 갱신:
서버에서 토큰이 만료되었다는 에러 객체가 반환되면 클라이언트는 Refresh Token이 key인 key인 쿠키값을 가져와 재발급 API를 호출해 쿠키를 갱신한다.

 

 

axiosInstance.interceptors.request.use((config) => {
    if (config.url === '/api/reissue') {
        // 토큰 재발급 요청일 때만 헤더에 refresh_token 넣어서 보내기
        config.headers.RefreshToken = getRefreshToken();
    } else {
        // 그 외 요청은 헤더에 access_token 넣어서 보내기
        config.headers.Authorization = 'Bearer ' + getAccessToken()
    }
    return config;
});

 

JWT 토큰 재발급 프론트엔드 과정

JWT 토큰은 일정 시간이 지나면 만료되므로, 만료되기 전에 새로운 토큰을 발급받는 작업이 필요하다. 여기서는 axios 인터셉터를 사용했다.


요청 인터셉터 설정하기

먼저, 모든 API 요청에 토큰을 포함시키기 위해 요청 인터셉터를 설정.


토큰 재발급 요청일 때는 헤더에 refreshToken을 넣어서 보내고, 그 외 요청은 헤더에 accessToken을 넣어서 보낸다.

 

axiosInstance.interceptors.response.use(
    (response) => {
        return response;
    },
    async (error) => {
        const {config, response} = error;

        if (response.data.errorCode === 'J0003') {
            config.headers.Authorization = 'Bearer ' + await reIssuedToken();
            return axiosInstance(config);
        } else {
            window.location.href = '/logout';
        }
        return Promise.reject(error);
    }
);

 

 

J0003은 토큰 만료 오류 코드. 만료 오류가 발생하면 reIssuedToken 함수를 호출하여 새로운 토큰을 요청하고, 재요청.

 

const reIssuedToken = async () => {
    try {
        const res = await axiosInstance.get(`/api/reissue`);
        updateCookie(res);
        return getAccessToken();
    } catch (e) {
        console.log(e);
        return null;
    }
};

 

토큰 재발급 함수
reIssuedToken 함수는 API를 통해 새로운 access token을 요청하고, 쿠키를 업데이트 한 뒤 새로운 토큰을 반환.

 

function updateCookie(signInResponse) {
    const accessToken = signInResponse.data.accessToken;
    const refreshToken = signInResponse.data.refreshToken;

    // Access Token 쿠키 설정
    setCookie("accessToken", accessToken, 1);  // 1일 동안 유효

    // Refresh Token 쿠키 설정 (여기서는 24시간으로 설정)
    setCookie("refreshToken", refreshToken, 1);  // 1일 동안 유효
}

function setCookie(name, value, expDays) {
    const date = new Date();
    date.setTime(date.getTime() + expDays * 24 * 60 * 60 * 1000);

    // 쿠키 값 설정
    document.cookie = name + "=" + value + ";expires=" + date.toUTCString() + ";path=/";
}

 

updateCookie는 API 응답으로 받은 새로운 토큰을 쿠키에 저장하는 함수.

반응형