jwt토큰으로 사용자 인증을 할 경우 accesstoken이 만료 되었을 경우 더 이상 요청을 할 수 없게 된다. 이때 자동으로 refresh토큰을 이용해서 새로운 accesstoken을 사용하도록 interceptor 코드를 작성하여 사용자의 경험을 향상시키고자 한다.
const { cookies } = useCookies();
jwtApi = await isServerRunning();
jwtApi.interceptors.request.use(async config => {
if (!config.headers) return config;
const accessToken = cookies.get('access');
if (accessToken && config.headers) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
});
isServerRunning은 앞서 생성한 axios인스턴스이고 vue-usecookies를 활용하여 쿠키에 저장된 토큰을 가져와서 헤더에 설정한다. jwtApi.interceptors.request.use 구문을 활용해서 요청시마다 토큰을 설정한다.
jwtApi.interceptors.response.use(
response => response,
async error => {
if (error.config && error.response && error.response.status === 401) {
try {
console.log('jwtapi');
const refreshApi = await isServerRunning();
const { cookies } = useCookies();
const authStore = useAuthStore();
const originalRequest = error.config;
const refreshToken = cookies.get('refresh');
originalRequest._retry = true;
if (!refreshToken) {
throw new Error('Refresh token not found');
}
const response = await refreshApi.post(`users/token/refresh/`, {
refresh: refreshToken,
});
const newAccessToken = response.data.access;
console.log('accrefre', newAccessToken);
authStore.setUserToken(newAccessToken, refreshToken);
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
return jwtApi(originalRequest);
} catch (e) {
console.log(e, error);
await logout();
return Promise.reject(e);
}
}
},
);
}
return jwtApi;
응답코드가 401인 경우에 한정해서 try-catch문에 코드를 작성했다. await refreshApi.post 를 통해 새로운 accesstoken을 받고 쿠키에 설정한 후 jwtApi(originalRequest); 를 반환 함으로써 직전에 거절되었던 요청을 새로운 토큰으로 재요청 하도록 만들었다.
catch (e) {
console.log(e, error);
await logout();
return Promise.reject(e);
}
refreshtoken이 만료된 경우는 보안을 위해 강제 로그아웃 처리를 했다. 여기서 메인 화면으로 돌리기 위해 window.location.href('/')를 넣었었는데, 그러면 Promise.reject(e) 요청이 반환 되지 않고 무한으로 요청이 반복되어서 해당 코드를 빼버렸더니 해결되었다.
let jwtApi = null;
const setupjwtApi = async () => {
if (!jwtApi) {
const { cookies } = useCookies();
jwtApi = await isServerRunning();
jwtApi.interceptors.request.use(async config => {
if (!config.headers) return config;
const accessToken = cookies.get('access');
if (accessToken && config.headers) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
});
jwtApi.interceptors.response.use(
response => response,
async error => {
if (error.config && error.response && error.response.status === 401) {
try {
console.log('jwtapi');
const refreshApi = await isServerRunning();
const { cookies } = useCookies();
const authStore = useAuthStore();
const originalRequest = error.config;
const refreshToken = cookies.get('refresh');
originalRequest._retry = true;
if (!refreshToken) {
throw new Error('Refresh token not found');
}
const response = await refreshApi.post(`users/token/refresh/`, {
refresh: refreshToken,
});
const newAccessToken = response.data.access;
console.log('accrefre', newAccessToken);
authStore.setUserToken(newAccessToken, refreshToken);
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
return jwtApi(originalRequest);
} catch (e) {
console.log(e, error);
await logout();
return Promise.reject(e);
}
}
},
);
}
return jwtApi;
};