[axios] interceptors로 요청/응답 전 작업하기

moontag·2022년 10월 1일
4

프로젝트

목록 보기
6/6
  • interceptors 기능 : then 또는 catch로 처리되기 전에 요청과 응답을 가로챌수 있다.

1. interceptors란?

interceptors 단어의 뜻 : 가로채는 사람, 방해자, 장애물

axios interceptors는 중간에서 request나 response를 가로채가는 기능이다.

  • request에서는 요청을 보내기 전에 하는 작업이 가능하고
  • response에서는 서버에서 받은 응답이 return 되기 전(thencatch로 넘어가기 전)에 인터셉터로 가로채서 원하는 작업들을 추가할 수 있다.
  • 인터셉터를 추가했다가 삭제할 수도 있고
  • 커스텀 인스턴스에서도 인터셉터를 추가해서 사용할 수 있다.

사용 방법

// 요청 인터셉터
axios.interceptors.request.use(function (config) {
    // 1. 요청 전달되기 전 작업 처리
    // config를 설정할 수 있다
    return config;
  }, function (error) {
    // 2. 요청 에러가 있는 작업 처리
    return Promise.reject(error);
  });

// 응답 인터셉터
axios.interceptors.response.use(function (response) {
    // 응답 200번대 status일 때 응답 성공 직전 호출
    // 3. 이 작업 이후 .then()으로 이어진다
    return response;
  }, function (error) {
    // 응답 200번대가 아닌 status일 때 응답 에러 직전 호출
    // 4. 이 작업 이후 .catch()로 이어진다
    return Promise.reject(error);
  });

2. 사용예시

1. 로그인했으면 모든 헤더에 Authorization을 미리 담는 작업 가능

JWT Access 토큰을 사용할 때 매 API요청마다 로그인 여부를 확인해서 헤더에 Authorization을 넣지 않아도
요청 전 interceptors에서 설정해서 헤더에 토큰을 미리 넣을 수 있다.

  • 위 예시는 JWT를 로컬스토리지에 넣어서 저장한 경우에 해당된다.
    하지만 로컬스토리지는 XSS 공격에 취약한 보안 문제가 있기 때문에 토큰의 저장소로는 비권장되기 때문에 로컬스토리지로 구현한 경우에만 참고하길 바란다.

2. Access 토큰 만료됐을 때 케이스 처리 가능

Access 토큰이 만료됐는지 확인하여 Refresh 토큰을 헤더에 담는 세팅을 미리 할 수 있다. 만료가 됐는데도 Refresh 토큰없이 Access 토큰만 헤더에 담아서 요청을 보낸다면 로그인이 안되기 때문에, Refresh토큰으로 Access토큰을 재발급해오는 로직을 짤 수 있다.

3. [응답 전] 공통된 error 처리 가능

공통된 error들에 대한 처리가 있다면 응답이 then으로 넘어가기 전에 error 처리를 사전에 할 수 있다.






1. JWT + 로컬스토리지 저장 방식일 때 구현내용

JWT 인증방식 로그인 + 토큰 로컬스토리지에 저장

  • 로컬스토리지는 XSS공격에 취약하므로 이 방법이 정답이 아니다!
    특정 프로젝트에서 밑과 같이 구현했다.

JWT토큰 전달,갱신방식

  • 전달방식 - headers로 토큰 전달
  • 갱신방식 - Access 토큰이 만료되면 Refresh 토큰을 요청에 같이 전달. 응답으로 갱신된 토큰 받았음.

요청 전 interceptors

  1. access토큰 있으면 JWT 디코딩해서 만료시간 검사
  2. 만료됐으면 만료된 access + refresh 토큰 같이 헤더에 담아서 요청
  3. 만료안됐으면 access만 요청 전 헤더에 담는 작업 수행

응답 전 interceptors

  1. access 토큰 만료돼서 응답헤더에 새로운 access토큰이 받아지면
  2. 만료된 access토큰 localStorage에서 삭제 후 새 토큰으로 교체
  3. 이후 요청 헤더에 새 access토큰을 담기

구현코드

import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import { ACCESS_EXP_MESSAGE, CheckJWTExp } from 'utils/CheckJwtExp';
import {
  getLocalStorage,
  removeLocalStorage,
  setLocalStorage,
} from './localStorage';

axios.defaults.withCredentials = true;

/** 1. 요청 전 - access토큰있는데 만료되면 refresh토큰도 헤더담아서 요청보내기 */
axios.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    const accessToken = getLocalStorage('access_token');
    const refreshToken = getLocalStorage('refresh_token');
    if (accessToken) {
      /** 2. access토큰 있으면 만료됐는지 체크 */
      if (CheckJWTExp() === ACCESS_EXP_MESSAGE) {
        /** 3. 만료되면 만료된 access, refresh 같이 헤더 담아서 요청 */
        config.headers!.Authorization = `${accessToken}`;
        config.headers!.Refresh = `${refreshToken}`;
      } else {
        config.headers!.Authorization = `${accessToken}`;
      }
    }
    return config;
  },
  (error) => Promise.reject(error)
);

/** 4. 응답 전 - 새 access토큰받으면 갈아끼기 */
axios.interceptors.response.use(
  async (response: AxiosResponse) => {
    if (response.headers.authorization) {
      const newAccessToken = response?.headers?.authorization;
      removeLocalStorage('access_token'); // 만료된 access토큰 삭제
      setLocalStorage('access_token', newAccessToken); // 새걸로 교체
      response.config.headers = {
        authorization: `${newAccessToken}`,
      };
    }
    return response;
  },
  (error) => {
    //응답 200 아닌 경우 - 디버깅
    return Promise.reject(error);
  }
);

참고

Axios interceptors로 토큰 연장하는 법!
axios 공식문서

profile
터벅터벅 나의 개발 일상

0개의 댓글