Axios Interceptor(feat.JWT Token)

김재우·2023년 4월 3일
0

interceptors

목록 보기
1/1

요즘 근황을 얘기해보자면, 아침엔 CS 스터디를 진행하고 , 저녁 이후엔 FIXET 프로젝트를 진행했었는데 , 디자이너를 구해서 디자인 작업을 할동안 시간적 여유가 좀 생겼다. 이력서를 계속해서 수정하고 갈고 닦으면서 든 생각이 나의 메인 프로젝트는 환승시민인데, 메인 프로젝트임에도 불구하고 코딩을 시작한 지 얼마 되지 않았을때 밤새가면서 블로그에 의존하면서 코드를 짜놓았다보니 코드의 질이나 여러가지 부분에서 수정할것이 많아 보였다. 그래서 백엔드 리더분께 연락을 드려봤더니 그 분도 리팩토링을 하고 싶어하셨고, 그래서 결국 리팩토링을 진행하게 되었다. 디자이너도 구하고 있다. 오늘은 백엔드 분과 JWT 토큰을 도입해서 access Token 을 갈아끼우는 interceptor 를 구현해봤다.

JWT 토큰

먼저 설명하기에 앞서 왜 access Token 을 갈아 끼워야 하는가?

  • 정답은 JWT 토큰 인증 방식은 제 3자에게 토큰이 탈취되는 경우 보안에 취약하다는 단점이 있어 토큰에 유효기간을 부여하여 보안을 강화하는 방법인데, 유효기간이 짧으면 사용자는 계속 로그인을 다시 해야하기 때문에 불편해진다. 여기서 사용할 수 있는것이 refresh token 이다.

interceptors 란 ?

  • 인터셉터란 then 또는 catch 로 처리되기 전에 요청과 응답을 가로채는 방법이다.

  • refresh function

const refreshTokenFn = async () => {
  const token = getCookie("token");

  try {
    const { data } = await instance.post("/newtoken", { token: token });

    const acctoken = data?.acctoken;
    console.log(acctoken);
    if (!acctoken) {
      removeCookie("token");
    }
    setCookie("token", acctoken);
    return data;
  } catch (error) {
    console.log(error);
    removeCookie("token");
  }
};
const maxAge = 10000;

export const memoizedRefreshToken = mem(refreshTokenFn, {
  maxAge,
});
  • 먼저 refresh 를 시킬 수 있는 함수를 만든다. token은 쿠키에서 가져오고 쿠키는 따로 훅을 만들어서 사용했다.
    try 문을 돌아 서버에서 성공적으로 데이터를 받을때와 catch(error) 잡을때를 구분해서 만들었다. newtoken이라는 restful api 로 통신을 해서 새로운 acctoken 을 받는다. 만약 acctoken이 다르다면 cookie 에서 token 을 삭제하고 새로운 refresh 토큰으로 갈아껴준다. 그리고 다시 return data를 보낸다.
  • error 일땐 토큰을 삭제해준다.
  • mem 이라는 라이브러리를 사용했다. mem 이란? 요청값을 메모제이션 하여 만약에 acctoken 이 다르지 않다면 10초동안 메모화하여 api 통신을 줄이는것이다. 20번의 api통신을 했지만 refresh 토큰값이 달라지지 않았다면 20번의 api 통신을 1번으로 줄여주는 라이브러리이다.
// 인터셉터
instance.interceptors.request.use(
  async (config) => {
    const token = getCookie("token");
    console.log(token);
    if (token) {
      config.headers = {
        ...config.headers,
        Authorization: `Bearer ${token}`,
      };
    }
    return config;
  },
  (error) => Promise.reject(error)
);

instance.interceptors.response.use(
  (response) => response,
  async (error) => {
    const config = error.config;
    if (error.response.status === 401 && !config?.sent) {
      config.sent = true;
      const result = await memoizedRefreshToken();
      console.log(result);
      if (result?.acctoken) {
        config.headers = {
          ...config.headers,
          Authorization: `Bearer ${result?.acctoken}`,
        };
      }
      return instance(config);
    }
    return Promise.reject(error);
  }
);
  • 앞에 설명한 refresh 토큰이 갈아 끼워지면 서버에서 access token 이 만료가 되면 서버에서 response.status를 401로 보내준다. 우리는 이 response를 이용해서 아까 만들었던 메모화 되는 리프레시 함수를 이용해서 다시 config.headers 안에다가 토큰만 바꿔서 재요청을 서버에 보내면서 access token 및 refresh token 작업을 마칠 수 있다.
profile
프론트엔드 꾸준개발자입니다.

0개의 댓글