Axios.interceptors
별도의 Library가 아닌 axios에 포함된 기능이다. 요청이나 응답 전에 무엇인가를 수행해주거나, 오류 발생시에 수행할 것들을 미리 정의해둘 수 있다.
- axios.interceptors.request.use()
axios.interceptors.request.use(function (config){ // Do something before request is sent return config; }, function (error){ // Do something with Request error return Promise.reject(error); });
- axios.interceptors.response.use()
axios.interceptors.response.use(function (response){ // Do something with response data return response; }, function (error){ // Do something with Response error return Promise.reject(error); });
- Devtool로 본 나만의 axios.interceptors 처리 과정
- 사용
axios.interceptors.response.use( // 정상 응답처리 (config) => { return config }, // 오류 발생시 function (error) { const originalRequest = error.config; //AccessToken이 만료됬고, RefreshToken이 유효하다면 if(validateTimeRefreshtoken() &&!validateTimeAccesstoken()){ // Refreshtoken을 통해 Accesstoken을 재발급한다. return getAccesstokenWithRefreshtoken() .then(res => { // Response가 정상이라면 if(res.status === 200){ console.log(['Inteceptors.Response] got succeed'); sessionStorage.setItem('accessToken', res.data.accessToken); sessionStorage.setItem('memberId', res.data.memberId); sessionStorage.setItem('role', res.data.role); axios.defaults.header.common['accessToken'] = sessionStorage.getItem('accessToken'); // 실패했던 요청을 다시 수행한다. return axios(originalRequest); } }) } // Refreshtoken이 만료됬을때 else if (!validateTimeRefreshtoken()){ sessionStorage.clear(); localStorage.clear(); window.location.href = "http://localhost:3000"; alert("세션 만료 다시 로그인 해주세요."); } return Promise.reject(error); } );
axios.create()
- 사용자 정의 axios 객체를 만든다.
const loginInstance = axios.create(config => { config.headers['Content-Type'] = 'application/json'; })
jwt-decode
- JWT decoding을 도와주는 Library이다.
- Terminal에서 아래 명령어로 설치한다.
npm i jwt-decode
import * as jwt_decode from 'jwt-decode';
var decodePayload = jwt_decode(accessToken, {payload: true});
validateTimeAccessToken(), validateTimeRefreshToken()
const validateTimeAccesstoken = () => {
// sessionStorage에서 accessToken을 가져온다.
const accessToken = sessionStorage.getItem('accessToken');
// jwt를 decode 하여 payload를 추출한다.
const decodePayload = jwt_decode(accessToken, {payload: true});
// exp가 UNIX Time으로 나오기 때문에 변환을 해준다.
var exp = (new Date(decodePayload.exp * 1000).getTime());
var now = new Date().getTime();
// 변환된 값을 비교하고 Boolean type을 반환한다.
if(now < exp){
console.log("AccessToken is valid");
return true;
} else {
consoel.log("AccessToken is invalid");
return false;
}
}
getAtwithRefreshToken()
export const getAccesstokenWithRefreshtoken = () => {
getAtInstance.post(baseURL + "/getAt", "",
{
headers: { 'refreshToken' : localStorage.getItem('refreshToken')}
})
}
3. 상세 흐름
A. (React) Browser에서 Login을 한다. (Id, Password)
B. (React) axios에서 Login api를 호출한다.(axios.interceptors.request로 전역 설정된 axios를 호출하지 않기 위해 새로운 axios 인스턴스(loginInstance)를 생성하고 해당 인스턴스로 호출한다.)
C. (Spring) Controller에서 받고, Params의 (Id + Pw) = DB의(Id + Pw) 비교한다.
C_a : 일치시 Id와 Roles를 Claims에 넣은뒤, JWT(AccessToken(At),RefreshToken(Rt))를 생성한다.
C_b : 불일치시 Exception을 던지고, Failcode 반환한다.
C_b2 : Browser에서 실패 alert 표시한다.
D. (Spring) Map<String,String>구조의 ‘data’에 At, memberId, Role, Rt을 넣고 반환한다.
E. (React) Payload.data로 넘어온 값 저장한다.
- sessionStorage(At, memberId, Role)
- localStorage(Rt)
F. (React) 정보요청시 Request Header에 AccessToken을 키로 담아서 요청한다.
F_a : 요청 이후 error 발생시, axios.interceptors.response에서 오류 발생을 감지한다.
F_a_2 : (axios.interceptors.response) At와 Rt가 유효한지 검증한다.
F_a_2-a1 : AccessToken만 만료됬고 RefreshToken은 유효하다면, Rt를 request header에 넣어서 Back-End로 보낸다.
F_a_2-a2 : Back-End에서 RefreshToken을 Parsing한 뒤, Id 값을 추출한다. 추출한 Id로 해당 Column을 조회한뒤, RefreshToken값을 비교한다.
F_a_2-a3 : 일치하다면 AccessToken을 재발급해서 전송하고 ‘E’에서의 행동과 동일하게 처리한다.
F_a_2-b1 : AccessTokne과 RefreshToken이 전부 만료됬다면, sessionStorage와 localStorage의 내용을 지우고 초기화면(로그인)으로 이동시킨 후 세션 만료에 대한 alert를 표시한다.
G. (Spring) 요청을 받은 Back-End는 AccessToken을 검증하고 유효 하다면 요청 정보를 제공한다.
F ~ G의 과정을 계속해서 반복한다.
'개발' 카테고리의 다른 글
React Native Expo 설치 및 실행 (0) | 2020.07.14 |
---|---|
SQLite(수정중) (0) | 2020.04.01 |
Android 폴더 옵션 (0) | 2020.04.01 |
Activity LifeCycle (0) | 2020.04.01 |
React js VS Vue js (0) | 2020.03.31 |