티스토리 뷰
728x90
반응형
vue 정리 - login (로그인) part2
login par1. 에 이어서 jwt 즉 json web token 설정에 대해서 정리해보고자 한다.
이제 vue 에서 token 정보 저장 후 바로 headers 의 Authorization 에 token 을 담아서 사용자 정보 호출하는
것을 살펴 보자.
우선 보통은 axios 로 통신할 때 headers 설정을 아래와 같이 하게 된다.
axios.post(`통신할 api 주소`, { id, password },
{
headers: {
'Authorization': `Bearer 토큰값`
});
하지만 통신할 api 들이 많은데 매번 저렇게 headers 부분을 삽입해서 전송하기엔 좀 거시기 하다...
그래서 axios 의 intercepters 를 활용해서 해당 부분을 해결할 수 있다.
아래는 axios 설정에 같이 로드하여 쓸 수 있게 intercepters 만 별도의 클래스를 만들었다.
jwtService.ts
import store from '@/store';
import router from '@/router';
import AuthConfig from '@/core/auth/config';
import { AxiosRequestConfig, AxiosResponse, AxiosStatic } from 'axios';
import { getToken } from '@/core/auth/utils';
import { AuthService } from '@/restApi';
import { UserMutationType } from '@/store/moduleType/AuthMutationTypes';
import { TokenActionType } from '@/store/moduleType/AuthActionTypes';
export default class JwtService{
private readonly axiosInstance: AxiosStatic;
//대기요청 상태인지 체크 toggle 변수
private isTokenRefreshCheck: boolean=false;
//콜백함수 타입의 배열
private refreshSubscribers: Array<(token: string)=>void>=[];
constructor(axiosInstance: AxiosStatic ) {
this.axiosInstance=axiosInstance;
/**
* request interceptor
*/
this.axiosInstance.interceptors.request.use( (config: AxiosRequestConfig)=>{
const token=getToken();
//토큰이 localstorage 에 있을 때만 header 에 토큰을 심어둔다.
if (token) {
//config.headers.Authorization 과 axios.defaults.headers.common.Authorization 은 서로 다르다.
config.headers.Authorization=`${AuthConfig.TOKEN_TYPE}${token}`;
}
return config;
}, (error: any)=>{
return Promise.reject( error );
} );
/**
* response interceptor
*/
this.axiosInstance.interceptors.response.use( (response: AxiosResponse)=>{
return response;
}, async (error: any)=>{
const { status, config, data }=error.response;
const responseConfig=config;
if(status === 401 ){
//로그인 실패시~
if (String( config.url ).includes( 'auth/login' ) && data.code === 700) {
store.commit( `Auth/${ UserMutationType.LOG_IN }`, false );
}else if(data.code===611){
if (!this.isTokenRefreshCheck) {
// isTokenRefreshing 이 false 인 경우에만 token refresh 요청
this.isTokenRefreshCheck=true;
// refresh token 요청
AuthService.fetchRefreshToken().then( (res: any)=>{
this.isTokenRefreshCheck=false;
const { accessToken, refreshToken }=res;
this.setTokens( accessToken, refreshToken );
setTimeout( async ()=>{
// 새로운 토큰으로 지연되었던 요청 진행
await this.getTokenRefreshed( accessToken );
//저장 배열 초기화
await this.removeRefreshSubscribers();
}, 700 );
} ).catch( (error: any)=>{
const { code, message, status }=error.data;
// console.log( error, code, message );
// refresh token 정보도 만료 되었을 때 로그인 페이지로 보낸다.
if (status === 401 && message === 'token expired') {
alert( '사용자 정보가 만료되었습니다.\\n 다시 로그인 해주세요' );
//로그아웃
this.shouldUnAuthorized();
}
} );
}
// token 이 재발급 되는 동안의 요청은 refreshSubscribers 에 저장
return new Promise( (resolve)=>{
//getTokenRefreshed 에서 전달된 token 을 내부에서 refreshSubscribers( 콜백함수 저장한 배열 ) 를 forEach 로 순환 대입( 전달된 token) 실행시킨다.
this.addRefreshSubscriber( (token: string)=>{
responseConfig.headers.Authorization=`${ AuthConfig.TOKEN_TYPE }${ token }`;
resolve( this.axiosInstance( responseConfig ) );
} );
} );
}else if (data.code === 613) { //613 : 갱신 토큰 만료 >> '화면 이동 (로그인)'
alert( '사용자 정보가 만료되었습니다. 로그인 해 주세요~' );
//로그아웃 시키기.
await this.shouldUnAuthorized();
}else if (data.code === 612) {
alert( '인증되지 않은 사용자 입니다. 로그인 해 주세요~' );
await this.shouldUnAuthorized();
}
}
// Do something with response error
return Promise.reject( error );
} );
}
/**
* 새로 발급 받는 token 재지정.
* @param token
* @param refreshToken
*/
public async setTokens( token: string, refreshToken: string){
await store.dispatch( `Auth/${ TokenActionType.SIGN_IN_BY_TOKEN }`, { token, refreshToken } );
};
/**
* 콜백함수 타입의 배열 초기화
*/
private removeRefreshSubscribers(){
this.refreshSubscribers=[];
};
/**
* 실행 콜백함수 배열 대입.
* @param callback
*/
private addRefreshSubscriber( callback: (token: string)=> void){
this.refreshSubscribers.push( callback );
};
/**
* 배열에 저장된 콜백함수( addRefreshSubscriber ) 실행.
* @param token
*/
private getTokenRefreshed(token: string){
this.refreshSubscribers.forEach( (callback: (token: string)=>void)=>callback( token ) );
};
/**
* 로그아웃 시키기
*/
private shouldUnAuthorized(){
///login?rPath=${encodeURIComponent(location.pathname)}
store.commit( `Auth/${ UserMutationType.LOGOUT }` );
router.push( { path: '/login', query:{rPath:new Date().getTime().toString()}} )
.then( ()=>{
console.log( '로그아웃' );
} );
}
}
- 해당 interseptors 를 이용해 api 통신마다 headers.Authorization 을 설정할 필요가 없게 되었다.
그리고 마지막으로 서버에서 Authorization 체크하여 해당 사용자 정보 client ( vue ) 에 전송은 이전에 AuthModule.ts 에서
store action 부분인 UserActionType.LOGIN 에서 처리가 된다.
아래는 AuthModule.ts 에서 해당 부분만 발췌했다.
/**
* 로그인~
* @param payload
*/
@Action( { rawError: true } )
public [UserActionType.LOGIN](payload: { id: string, password: string }): Promise<any> {
const { id, password }=payload;
//LOGIN_ACTION
return AuthService.login( id, password )
.then( (data: any)=>{
this.context.commit( TokenMutationType.GET_TOKEN, data.accessToken );
this.context.commit( TokenMutationType.GET_REFRESH_TOKEN, data.refreshToken );
return AdminService.getMe()
.then( (data: any)=>{
this.context.commit( UserMutationType.INFO, data );
return Promise.resolve( 'signin status' );
} );
} ).catch( (error: any)=>{
return Promise.reject( error );
} );
}
728x90
반응형
'Programming language > vuejs' 카테고리의 다른 글
vue+ts 유용한 Utils ( js 에서 ts 변환 ) (0) | 2022.05.30 |
---|---|
axios interceptors 를 활용한 vue + ts + jwt ( token/refreshToken )정리 (0) | 2022.05.25 |
vue 정리 part3 - Vue-router (0) | 2022.05.17 |
vue 정리 - login(로그인) part1 (0) | 2022.05.06 |
vue 정리 part1 - vue 설정. (0) | 2022.05.02 |
댓글
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- Angular
- react-router-dom
- cordova
- Intrinsic
- anime.js
- Aptana
- 리프래시토큰
- git checkout -b
- 반복문
- Vue3
- git
- svg icon font
- interceptors
- react
- 아이콘 폰트 만들기
- IntrinsicElements
- JsDoc
- 자바스크립트
- 내장요소
- RefreshToken
- 태그
- icon font
- React.StrictMode
- vue-router
- svg 폰트
- svg모션
- 코도바
- 앵귤러
- CSS
- for of 구문
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함