axios jwt interceptor

김혁준·2024년 2월 23일
0

Vue3

목록 보기
2/5

jwt토큰으로 사용자 인증을 할 경우 accesstoken이 만료 되었을 경우 더 이상 요청을 할 수 없게 된다. 이때 자동으로 refresh토큰을 이용해서 새로운 accesstoken을 사용하도록 interceptor 코드를 작성하여 사용자의 경험을 향상시키고자 한다.

  1. 요청시 자동으로 헤더에 accesstoken 설정
const { cookies } = useCookies();
    jwtApi = await isServerRunning();
    jwtApi.interceptors.request.use(async config => {
      if (!config.headers) return config;
      const accessToken = cookies.get('access');
      if (accessToken && config.headers) {
        config.headers.Authorization = `Bearer ${accessToken}`;
      }
      return config;
    });

isServerRunning은 앞서 생성한 axios인스턴스이고 vue-usecookies를 활용하여 쿠키에 저장된 토큰을 가져와서 헤더에 설정한다. jwtApi.interceptors.request.use 구문을 활용해서 요청시마다 토큰을 설정한다.

  1. 401에러 발생시(토큰이 유효하지 않은 경우) 새로운 accesstoken요청 후 쿠키에 저장 후 다시 요청
 jwtApi.interceptors.response.use(
      response => response,
      async error => {
        if (error.config && error.response && error.response.status === 401) {
          try {
            console.log('jwtapi');
            const refreshApi = await isServerRunning();
            const { cookies } = useCookies();
            const authStore = useAuthStore();
            const originalRequest = error.config;
            const refreshToken = cookies.get('refresh');
            originalRequest._retry = true;
            if (!refreshToken) {
              throw new Error('Refresh token not found');
            }
            const response = await refreshApi.post(`users/token/refresh/`, {
              refresh: refreshToken,
            });
            const newAccessToken = response.data.access;
            console.log('accrefre', newAccessToken);
            authStore.setUserToken(newAccessToken, refreshToken);
            originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
            return jwtApi(originalRequest);
          } catch (e) {
            console.log(e, error);
            await logout();
            return Promise.reject(e);
          }
        }
      },
    );
  }
  return jwtApi;

응답코드가 401인 경우에 한정해서 try-catch문에 코드를 작성했다. await refreshApi.post 를 통해 새로운 accesstoken을 받고 쿠키에 설정한 후 jwtApi(originalRequest); 를 반환 함으로써 직전에 거절되었던 요청을 새로운 토큰으로 재요청 하도록 만들었다.

  1. refreshtoken 자체가 만료된 경우
catch (e) {
            console.log(e, error);
            await logout();
            return Promise.reject(e);
          }

refreshtoken이 만료된 경우는 보안을 위해 강제 로그아웃 처리를 했다. 여기서 메인 화면으로 돌리기 위해 window.location.href('/')를 넣었었는데, 그러면 Promise.reject(e) 요청이 반환 되지 않고 무한으로 요청이 반복되어서 해당 코드를 빼버렸더니 해결되었다.

원본 코드

let jwtApi = null;
const setupjwtApi = async () => {
  if (!jwtApi) {
    const { cookies } = useCookies();
    jwtApi = await isServerRunning();
    jwtApi.interceptors.request.use(async config => {
      if (!config.headers) return config;
      const accessToken = cookies.get('access');
      if (accessToken && config.headers) {
        config.headers.Authorization = `Bearer ${accessToken}`;
      }
      return config;
    });

    jwtApi.interceptors.response.use(
      response => response,
      async error => {
        if (error.config && error.response && error.response.status === 401) {
          try {
            console.log('jwtapi');
            const refreshApi = await isServerRunning();
            const { cookies } = useCookies();
            const authStore = useAuthStore();
            const originalRequest = error.config;
            const refreshToken = cookies.get('refresh');
            originalRequest._retry = true;
            if (!refreshToken) {
              throw new Error('Refresh token not found');
            }
            const response = await refreshApi.post(`users/token/refresh/`, {
              refresh: refreshToken,
            });
            const newAccessToken = response.data.access;
            console.log('accrefre', newAccessToken);
            authStore.setUserToken(newAccessToken, refreshToken);
            originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
            return jwtApi(originalRequest);
          } catch (e) {
            console.log(e, error);
            await logout();
            return Promise.reject(e);
          }
        }
      },
    );
  }
  return jwtApi;
};

0개의 댓글

관련 채용 정보