fix(web): 会话失效时强制清本地 token,避免卡死无法进入登录页

坏 JWT 会导致 logout 接口失败,原先 removeToken 执行不到,且 getInfo 失败后跳到 / 形成死循环。

Confidence: high
Scope-risk: narrow
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
“wuzhen”andCursor committed 2026-10-26 15:50:34 +08:00
1 parent 937cbb6bbd
commit eeae0af978
2 files changed
+14 -8

No files matched your search

+3 -2
View File
@@ -37,6 +37,7 @@ router.beforeEach(async (to, from, next) => {
to.meta.title && useSettingsStore().setTitle(to.meta.title as string); to.meta.title && useSettingsStore().setTitle(to.meta.title as string);
/* has token*/ /* has token*/
if (to.path === '/login') { if (to.path === '/login') {
// 已有 token 时先进首页;若会话已失效,下面 getInfo 失败会清 token 并回登录页
next({ path: '/' }); next({ path: '/' });
NProgress.done(); NProgress.done();
} else if (isWhiteList(to.path)) { } else if (isWhiteList(to.path)) {
@@ -47,9 +48,9 @@ router.beforeEach(async (to, from, next) => {
// 判断当前用户是否已拉取完user_info信息 // 判断当前用户是否已拉取完user_info信息
const [err] = await tos(useUserStore().getInfo()); const [err] = await tos(useUserStore().getInfo());
if (err) { if (err) {
isRelogin.show = false;
await useUserStore().logout(); await useUserStore().logout();
// ElMessage.error(err.message || '获取用户信息失败'); next(`/login?redirect=${encodeURIComponent(to.fullPath || '/')}`);
next({ path: '/' });
} else { } else {
isRelogin.show = false; isRelogin.show = false;
const accessRoutes = await usePermissionStore().generateRoutes(); const accessRoutes = await usePermissionStore().generateRoutes();
+11 -6
View File
@@ -65,13 +65,18 @@ export const useUserStore = defineStore('user', () => {
return Promise.reject(err); return Promise.reject(err);
}; };
// 注销 // 注销(后端失败也不能挡住清本地 token,否则坏 JWT 会导致永远进不了登录页)
const logout = async (): Promise<void> => { const logout = async (): Promise<void> => {
await logoutApi(); try {
token.value = ''; await logoutApi();
roles.value = []; } catch {
permissions.value = []; // ignore:token 已失效/签名无效时服务端注销也会失败
removeToken(); } finally {
token.value = '';
roles.value = [];
permissions.value = [];
removeToken();
}
}; };
const setAvatar = (value: string) => { const setAvatar = (value: string) => {