feat(owner-vue): JWT refresh Token 로직 추가

- 페이지 이동 시 유효기간 판단 후 reissue 호출 로직 추가
- api 호출 시 response code에 따라 reissue 호출 로직 추가 (code => EXPIRED 일 경우)
This commit is contained in:
bum12ark
2022-02-28 16:47:04 +09:00
parent 731e79ece6
commit 516c192211
5 changed files with 128 additions and 10 deletions

26
owner-vue/src/api/auth.js Normal file
View File

@@ -0,0 +1,26 @@
import axios from "axios";
import jwt from "@/common/jwt";
export default {
async requestReissue() {
const config = {
headers: {
"X-AUTH-TOKEN": jwt.getToken()
}
}
const res = await axios.get("http://localhost:8001/user-service/auth/reissue", config);
const accessToken = res.data.data.accessToken;
jwt.saveToken(accessToken);
jwt.saveExpiredTime(res.data.data.expiredTime);
axios.defaults.headers.common['Authorization'] = "Bearer " + accessToken;
return accessToken;
},
requestCheckAccessToken() {
axios.defaults.headers.common['Authorization'] = "Bearer " + jwt.getToken();
return axios.get("http://localhost:8001/user-service/auth/check/accessToken");
}
}

View File

@@ -1,3 +1,5 @@
import jwt from '../common/jwt.js';
export default { export default {
requestRegisterUser(user) { requestRegisterUser(user) {
return axios.post("http://localhost:8001/user-service/store-owner", user); return axios.post("http://localhost:8001/user-service/store-owner", user);
@@ -11,10 +13,12 @@ export default {
try { try {
const response = await axios.post("http://localhost:8001/user-service/login", user); const response = await axios.post("http://localhost:8001/user-service/login", user);
console.log(response); const data = response.data.data;
const AUTH_TOKEN = response.data.data.access_token;
localStorage.setItem('access_token', AUTH_TOKEN); jwt.saveToken(data.accessToken);
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; jwt.saveExpiredTime(data.expiredTime);
axios.defaults.headers.common['Authorization'] = "Bearer " + data.accessToken;
return true; return true;
} catch (err) { } catch (err) {

View File

@@ -0,0 +1,38 @@
const moment = require('moment');
const ACCESS_TOKEN_NAME = "accessToken";
const EXPIRED_TIME_NAME = "expiredTime";
const tag = "[jwt]";
export default {
getToken() {
return localStorage.getItem(ACCESS_TOKEN_NAME);
},
saveToken(token) {
localStorage.setItem(ACCESS_TOKEN_NAME, token);
},
getExpiredTime() {
return localStorage.getItem(EXPIRED_TIME_NAME);
},
saveExpiredTime(expiredTime) {
localStorage.setItem(EXPIRED_TIME_NAME, expiredTime);
},
destroyAll() {
localStorage.removeItem(ACCESS_TOKEN_NAME);
localStorage.removeItem(EXPIRED_TIME_NAME);
},
isExpired() {
const expiredTime = this.getExpiredTime();
const expiredMoment = moment(expiredTime);
let currentMoment = moment();
const difference = moment.duration(expiredMoment.diff(currentMoment)).asSeconds();
console.log(tag, "expireMoment = ", expiredMoment, "currentMoment = ", currentMoment, "diff = ", difference);
// 만료 30초 전일 경우 만료로 판단
return difference <= 30;
}
}

View File

@@ -1,7 +1,11 @@
import Vue from 'vue' import Vue from 'vue';
import App from './App.vue' import App from './App.vue';
import vuetify from './plugins/vuetify' import vuetify from './plugins/vuetify';
import router from './router' import router from './router';
import axios from "axios";
import auth from "./api/auth.js"
axios.defaults.withCredentials = true;
Vue.config.productionTip = false Vue.config.productionTip = false
@@ -9,4 +13,33 @@ new Vue({
vuetify, vuetify,
router, router,
render: h => h(App) render: h => h(App)
}).$mount('#app') }).$mount('#app')
axios.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
try {
const originalRequest = error.config;
if (error.response.status === 401) {
// access token 만료 시
if (error.response.data.code == "EXPIRED") {
const accessToken = await auth.requestReissue();
originalRequest.headers.Authorization = "Bearer " + accessToken;
return axios(originalRequest);
}
// 그외 에러일 시
alert("로그인 정보가 일치하지 않습니다.");
await router.replace('/login');
return;
}
} catch (error) {
alert("로그인 정보가 일치하지 않습니다.");
await router.replace('/login');
return;
}
return Promise.reject(error);
}
);

View File

@@ -4,13 +4,30 @@ import VueRouter from 'vue-router'
import DashboardLayout from "@/views/Layout/DashboardLayout"; import DashboardLayout from "@/views/Layout/DashboardLayout";
import AuthLayout from "@/views/Layout/AuthLayout"; import AuthLayout from "@/views/Layout/AuthLayout";
import jwt from "../common/jwt.js";
import auth from "../api/auth.js";
Vue.use(VueRouter) Vue.use(VueRouter)
const authCheck = async function (to, from, next) {
try {
if (jwt.isExpired()) {
// refresh 호출
await auth.requestReissue();
} else {
await auth.requestCheckAccessToken();
}
} catch (error) {
await router.replace("/login");
}
next();
};
const routes = [ const routes = [
{ {
path: '/dashboard', path: '/dashboard',
redirect: 'dashboard', redirect: 'dashboard',
component: DashboardLayout, component: DashboardLayout,
beforeEnter: authCheck,
children: [ children: [
{ {
path: "/dashboard", path: "/dashboard",
@@ -64,4 +81,4 @@ const router = new VueRouter({
routes routes
}) })
export default router export default router