fix: deduplicate expired token handling #35
+9
-1
@@ -1,4 +1,5 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { TOKEN_KEY, TOKEN_EXPIRE_KEY, USER_INFO_KEY } from '@/config/env.js'
|
||||
import AdminLayout from '../components/layout/AdminLayout.vue'
|
||||
import OperationLog from '@/views/system/OperationLog.vue'
|
||||
|
||||
@@ -809,7 +810,14 @@ router.beforeEach((to, from, next) => {
|
||||
document.title = to.meta.title ? `${to.meta.title} - 007UI管理系统` : '007UI管理系统'
|
||||
|
||||
// 这里可以添加登录验证逻辑
|
||||
const isAuthenticated = localStorage.getItem('token')
|
||||
const token = localStorage.getItem(TOKEN_KEY)
|
||||
const expire = Number(localStorage.getItem(TOKEN_EXPIRE_KEY))
|
||||
const isAuthenticated = !!token && Number.isFinite(expire) && expire > 0 && Date.now() < expire * 1000
|
||||
if (token && !isAuthenticated) {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
localStorage.removeItem(TOKEN_EXPIRE_KEY)
|
||||
localStorage.removeItem(USER_INFO_KEY)
|
||||
}
|
||||
if (to.path !== '/login' && !isAuthenticated) {
|
||||
next({ path: '/login' })
|
||||
} else {
|
||||
|
||||
+28
-23
@@ -46,6 +46,22 @@ const isTokenExpiringSoon = () => {
|
||||
let isRefreshing = false
|
||||
// 等待刷新token的请求队列
|
||||
let refreshSubscribers = []
|
||||
let authRedirecting = false
|
||||
|
||||
const clearAuthAndRedirect = (message = '登录过期,请重新登录') => {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
localStorage.removeItem(TOKEN_EXPIRE_KEY)
|
||||
localStorage.removeItem(USER_INFO_KEY)
|
||||
onTokenRefreshed(null)
|
||||
if (authRedirecting) return
|
||||
authRedirecting = true
|
||||
ElMessage.closeAll()
|
||||
ElMessage.warning(message)
|
||||
if (router.currentRoute.value.path !== '/login') router.replace('/login')
|
||||
}
|
||||
|
||||
// 鉴权失效后终止原页面请求链,避免并发请求进入各页面 catch 后重复弹错。
|
||||
const stopExpiredRequest = () => new Promise(() => {})
|
||||
|
||||
// 添加请求到队列
|
||||
const subscribeTokenRefresh = (callback) => {
|
||||
@@ -83,20 +99,12 @@ const doRefreshToken = async () => {
|
||||
}
|
||||
}
|
||||
// 刷新失败,触发登出逻辑
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
localStorage.removeItem(TOKEN_EXPIRE_KEY)
|
||||
localStorage.removeItem(USER_INFO_KEY)
|
||||
ElMessage.warning('登录过期,请重新登录')
|
||||
router.push('/login')
|
||||
clearAuthAndRedirect()
|
||||
return null
|
||||
} catch (error) {
|
||||
console.error('Token刷新失败:', error)
|
||||
// 刷新失败,触发登出逻辑
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
localStorage.removeItem(TOKEN_EXPIRE_KEY)
|
||||
localStorage.removeItem(USER_INFO_KEY)
|
||||
ElMessage.warning('登录过期,请重新登录')
|
||||
router.push('/login')
|
||||
clearAuthAndRedirect()
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -122,6 +130,10 @@ class Request {
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
if (error.response?.status === 401) {
|
||||
clearAuthAndRedirect()
|
||||
return stopExpiredRequest()
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
@@ -206,14 +218,8 @@ http2.interceptors.request.use(async config => {
|
||||
if (urlNeedAuth(config.url)) {
|
||||
// 检查token是否已过期
|
||||
if (isTokenExpired()) {
|
||||
if (token) {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
localStorage.removeItem(TOKEN_EXPIRE_KEY)
|
||||
localStorage.removeItem(USER_INFO_KEY)
|
||||
ElMessage.warning('登录过期,请重新登录')
|
||||
}
|
||||
router.push('/login')
|
||||
return Promise.reject(new Error('Token已过期'))
|
||||
clearAuthAndRedirect(token ? '登录过期,请重新登录' : '请先登录')
|
||||
return stopExpiredRequest()
|
||||
}
|
||||
|
||||
// 检查token是否即将过期,进行无感刷新
|
||||
@@ -251,6 +257,7 @@ http2.interceptors.request.use(async config => {
|
||||
})
|
||||
} else {
|
||||
// 正常情况,直接使用token
|
||||
authRedirecting = false
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
}
|
||||
@@ -269,14 +276,12 @@ http2.interceptors.response.use(
|
||||
}
|
||||
const { status } = error.response;
|
||||
if (status === 401) {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
ElMessage.warning('登陆过期,请重新登陆')
|
||||
router.push('/login')
|
||||
return Promise.reject();
|
||||
clearAuthAndRedirect()
|
||||
return stopExpiredRequest()
|
||||
}
|
||||
// 其他错误处理(可选)
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default request
|
||||
export default request
|
||||
|
||||
Reference in New Issue
Block a user