사실 Promise, fetch를 대신하여 사용하기 매우 편리한 Axios를 예전부터 사용해왔다. 하지만 오늘 매우 개꿀 기능을 알아와서 공유하고자 포스팅한다.
대충 개념은 아래 사진과 같다.
use()
메서드로 등록되어있는 함수를 실행한다. 그럼 이를 이용하여 토큰을 아주 편하게 조리할 수 있다.import axios from 'axios';
const instance = axios.create({
baseURL: 'YOUR_API_BASE_URL',
});
instance.interceptors.request.use(
async (config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
async (error) => {
if (error.response && error.response.status === 401) {
const refreshToken = localStorage.getItem('refreshToken');
if (refreshToken) {
try {
const response = await axios.post('/api/refresh-token', { refreshToken });
const newAccessToken = response.data.accessToken;
localStorage.setItem('token', newAccessToken);
// 원래 req를 요청
const originalRequest = error.config;
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
return axios(originalRequest);
} catch (refreshError) {
// 리프레시 토큰을 사용한 토큰 갱신에 실패한 경우 로그아웃 또는 다른 조치를 취할 수 있다.
// 여기서는 그냥 localstorage를 밀어버렸다.
localStorage.clear();
}
}
}
return Promise.reject(error);
}
);
export default instance;
즉, Axios 인스턴를 사용하여 req를 날리기 이전에 토큰 검사 미들웨어를 추가해야 한다.
이렇게 구현하면 Axios를 사용하여 REST API를 호출하면 모든 요청 이전에 토큰의 유효성이 검사된다.
토큰이 없거나 만료된 경우, 서버에서 적절한 응답을 보내므로 클라이언트에서 해당 응답을 처리할 수 있다.
아래는 내 상황에 맞는 예제코드이다.
instance_Api_A.interceptors.request.use(
async (config) => {
const token = getCookie('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`;
config.headers["Content-Type"] = 'application/json';
}
return config;
},
async (error) => {
// 우리는 403 forbidden으로 넘어온다.
if (error.response && error.response.status === 403) {
const refreshToken = getCookie('refreshToken')
if (refreshToken) {
// 리프레시 토큰을 사용하여 새로운 액세스 토큰을 요청
try {
const userId = localStorage.getItem('userId');
const payload = {userId, refreshToken}
const {data} = await instance_Api_A.post('/common/token-refresh', {payload });
const newAccessTokenData = data.tokenInfoDTO;
const formattedDate1 = formatDate(newAccessTokenData.tokenExpDt)
const formattedDate2 = formatDate(newAccessTokenData.refreshExpDt)
document.cookie = `token=${newAccessTokenData.token}; expires=${formattedDate1}; path=/;`
document.cookie = `refreshToken=${newAccessTokenData.refresh}; expires=${formattedDate2}; path=/;`
const originalRequest = error.config;
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
return axios(originalRequest);
} catch (refreshError) {
localStorage.clear();
$router.push('/login'); // 여기는 vue.js 문법이다.
}
}
}
return Promise.reject(error);
}
);