공부/React

axios로 refreshToken 관리

choryDev 2020. 10. 2. 01:22

axios의 인터셉터를 이용하여

엑세스토큰이 만료  되었을 경우 각 함수마다 처리하는게 아닌 공통으로

리프레쉬토큰을 재발급 받아 다시 함수를 처리 하는 방법을 설명하도록 하겠다.

인터셉터란? 

then이나catch로 처리되기 전에 요청이나 응답을 가로채는 것 이다.

 

전체 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import axios from 'axios';
import GLOBALS from 'src/common/globals';
 
const axiosApiInstance = axios.create();
 
//Request interceptor for API calls
axiosApiInstance.interceptors.request.use(
  async config => {
    const userInfo = window.sessionStorage.getItem('userInfo');
    const accessToken = userInfo ? JSON.parse(userInfo).accessToken : null;
    config.headers = { 
      'Authorization': `Bearer ${accessToken}`,
      'Accept''application/json',
    }
    return config;
  },
  error => {
    Promise.reject(error)
});
 
// Response interceptor for API calls
axiosApiInstance.interceptors.response.use((response) => {
  return response
}, async function (error) {
  const originalRequest = error.config;
  if (error.response.status === 401 && !originalRequest._retry) {
    console.log('토큰 만료')
    originalRequest._retry = true;
    const sessionObj = window.sessionStorage.getItem('userInfo');
    let userInfo = sessionObj ? JSON.parse(sessionObj) : null;
    const access_token = await refreshAccessToken(userInfo.refreshToken);
    if(userInfo){
      originalRequest.headers['Authorization'= 'Bearer ' + access_token;
      userInfo.accessToken = access_token;
      window.sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
    }
    return axios(originalRequest);
  }
  return Promise.reject(error);
});
cs

 

1.  인터셉터를 사용할 axios 인스턴스를 생성을 한다.

1
2
3
4
5
import axios from 'axios';
import GLOBALS from 'src/common/globals';
 
const axiosApiInstance = axios.create();
 
cs

 

2. 생성한 axios 인스턴스에서 요청을 할때 공통으로 선언한 설정부분.

나는 세션 스토리지에 accessToken을 담았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
axiosApiInstance.interceptors.request.use(
  async config => {
    const userInfo = window.sessionStorage.getItem('userInfo');
    const accessToken = userInfo ? JSON.parse(userInfo).accessToken : null;
    config.headers = { 
      'Authorization': `Bearer ${accessToken}`,
      'Accept''application/json',
      'Content-Type''application/x-www-form-urlencoded'
    }
    return config;
  },
  error => {
    Promise.reject(error)
});
cs

 

3. 앞에서 생성한 axios 인스턴스에서 인터셉터를 걸어 리프레쉬 토큰 제발급

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Response interceptor for API calls
axiosApiInstance.interceptors.response.use((response) => {
  return response
}, async function (error) {
  const originalRequest = error.config;
  if (error.response.status === 401 && !originalRequest._retry) {
    console.log('토큰 만료')
    originalRequest._retry = true;
    const sessionObj = window.sessionStorage.getItem('userInfo');
    let userInfo = sessionObj ? JSON.parse(sessionObj) : null;
    const access_token = await refreshAccessToken(userInfo.refreshToken);
    if(userInfo){
      originalRequest.headers['Authorization'= 'Bearer ' + access_token;
      userInfo.accessToken = access_token;
      window.sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
    }
    return axios(originalRequest);
  }
  return Promise.reject(error);
});
cs

6줄: 만약 에러 발생 시 error객체 안의 responese.status를 이용하여

        에러의 내용을 확인하여 상황에 맞게 처리 할 수 있게 하였다

        401처럼 인증되지 않은 사용자 일 경우를 확인과

        error.config._retry 객체에서 혹시 앞에서 또 함수를 호출 하지 않았는지 체크를 한다

 

11줄: 내가 만든 refreshAccessToken 함수로 세션 스토리지에 저장된 리프레쉬 토큰으로 액세스 토큰을 다시 재발급 받는다.

 

13줄: 앞에서 요청을 실패한 정보가 담긴 originalRequest의 headers의 토큰 값을

            재발급 받은 accessToken으로 교체한다.

 

15줄: 재발급 받은 accessToken을 다시 세션스토리지에 저장을 한다.

 

17줄: 재발급 accessToken으로 교체된 앞에서 요청 실패한 객체를 다시 요청한다.

 

 

이번 예제에서는 인증되지 않은 토큰만 처리를 하였지만

응답 코드의 상황에 따라 응용 할 수 있을 것 이다.

 

나 같은 경우는 refreshToken 함수 안에서 알림 메시지와 페이지 이동을 시켰다.

 

미흡한 설명이지만 봐주셔서 감사합니다.

혹시 더좋은 방법 있을 경우 알려주시면 감사하겠습니다. ^^