axios interceptor을 이용한 토큰 처리

Jin·2022년 4월 12일
2

token

목록 보기
1/1

1. 들어가기에 앞서

인증 및 보안에 대해 한번도 배운적없던 나로서는 토큰 처리를 어떻게 하는지 항상 궁금하였다. 국내외 사이트들을 찾아봐도 어떤곳에서는 쿠키를 사용해라 또 다른곳에서는 로컬스토리지를 사용해라 모두가 다른말들을 할뿐이었고 결국 정답은 없다는것을 알겠되었다.(혹시 있다면 댓글로 알려주시면 감사하겠습니다)

지난번 프로젝트에서는 해답을 찾지 못하고 시간도 부족하여 쿠키에 리프레시 토큰과 액세스 토큰을 둘다 저장하는 말도 안되는짓을 하였었기에 이번에는 처음부터 토큰 처리를 하고 프로젝트를 진행하기로 했다.

2. 토큰 처리 과정

1) 로그인시

  • 로그인요청 및 로그인 성공시 JWT토큰 생성
  • 서버에서 쿠키에 accessToken과 refreshToken의 index를 저장
  • 이후부터 클라이언트에서 서버에 요청시 authorization header를 추가하여 요청
  • 유효성 체크(JwtFilter로 확인) 및 반환

2) 액세스 토큰 유효기간 만료시

  • headers에 accessToken을 설정하여 요청
  • accessToken 유효 기간 만료시 해당 에러코드를 서버에서 반환
  • accessToken 유횩 기간 만료 에러코드를 받으면 클라이언트에서 토큰 accessToken과 index를 담아 서버에 reissue 요청
  • 서버에서 accessToken과 index의 유효성 검사
  • 일치하면 토큰을 새로 발급하고 쿠키에 저장 => 이전에 요청하였던 작업 수행
  • 실패하면 실패 에러코드를 클라이언트에 반환 => 클라이언트에서는 로그아웃 처리

3. 코드 작성

토큰을 재발급 할때는 header에 accessToken을 전달하면 안되므로 setInterceptors에서 isReissue라는 매개 변수를 지정하여 이것으로 reissue를 하는것인지 아닌지를 구별하였다.
또한 사용자 경험 입장에서는 accessToken의 유효기간이 만료가 된걸 모르는것이 더 좋으므로, 리이슈가 완료되었을때는 그 전의 요청을 다시 보내주는 코드를 작성하였다.

사실 createInstanceauthCreateInstance의 차이는 true 값을 보내주고 말고의 차이인데 불필요하게 코드를 많이 작성한것 같은 느낌이다. 더 좋은 방법을 알고 계시면 댓글 달아주시면 감사하겠습니다.

import axios, { AxiosInstance } from "axios";
import cookie from "react-cookies";
import authApi from "./auth";
import errorMessage from "store/error";

axios.defaults.withCredentials = true;

const setInterceptors = (instance: AxiosInstance, isReissue?: boolean) => {
	instance.interceptors.request.use(
		(config) => {
			if (isReissue) return config;
			const token = cookie.load("access_token");
			if (config.headers && token) config.headers.Authorization = `Bearer ${token}`;
			return config;
		},
		(error) => Promise.reject(error),
	);
	instance.interceptors.response.use(
		(response) => {
			return response;
		},
		(error) => {
			const index = cookie.load("index");
			const access_token = cookie.load("access_token");
			if (error.response.data.error_code === "A01") {
				authApi.reissue({ index, access_token });
				return instance.request(error.config);
			}
			if (error.response.data.error_code === "A08") {
				return authApi.logout();
			}
			return errorMessage(error.response.data.error_code);
		},
	);
	return instance;
};

const createInstance = () => {
	const instance = axios.create({
		baseURL: process.env.REACT_APP_MAIN_URL,
		timeout: 10000,
		headers: { "Content-Type": "application/json" },
	});
	return setInterceptors(instance);
};

const authCreateInstance = () => {
	const instance = axios.create({
		baseURL: process.env.REACT_APP_MAIN_URL,
		timeout: 10000,
		headers: { "Content-Type": "application/json" },
	});
	return setInterceptors(instance, true);
};

export const authRequest = authCreateInstance();
export const request = createInstance();
profile
내가 다시 볼려고 작성하는 블로그

0개의 댓글