diff --git a/WebVue/src/router/index.ts b/WebVue/src/router/index.ts index 2b18b62..0de6256 100644 --- a/WebVue/src/router/index.ts +++ b/WebVue/src/router/index.ts @@ -73,9 +73,10 @@ function setupPermissionGuard() { if (PERMISSION_FREE_ROUTE_NAMES.includes(to.name as string)) return true; const permissionInfo = useLoginProfileStoreWithOut().getPermissionInfo(); - // 本地拿不到权限信息时放行:宁可少拦,也不要因为本地缓存异常把所有人挡在门外。 + // 本地拿不到权限信息、或权限清单为空时放行:宁可少拦,也不要因为本地缓存异常 + // (缓存过期、被写坏成空档案等)把所有人挡在 403 外面。 // 真正的安全边界在后端——每个接口都有 [PermissionOperate] 校验。 - if (!permissionInfo) return true; + if (!permissionInfo || !permissionInfo.Permissions?.length) return true; if (new PermissionContext(permissionInfo).canView(permission)) return true; return { path: "/error/page403", query: { from: to.fullPath } }; diff --git a/WebVue/src/store/modules/loginProfile.ts b/WebVue/src/store/modules/loginProfile.ts index 461ef15..59d08fe 100644 --- a/WebVue/src/store/modules/loginProfile.ts +++ b/WebVue/src/store/modules/loginProfile.ts @@ -34,13 +34,29 @@ export const useLoginProfileStore = defineStore("loginProfile", { updateJwtInfo(jwtInfo: JwtInfo) { storage.set(JWT_STORAGE_ID, "Bearer " + jwtInfo.AccessToken); storage.set(JWT_REFRESHKEY_STORAGE_ID, jwtInfo.RefreshToken); - // 同时同步内存里的登录信息:否则别处读 loginProfile.Token 拿到的还是旧令牌 - if (this.loginProfile?.Token) { - this.loginProfile.Token.AccessToken = jwtInfo.AccessToken; - this.loginProfile.Token.RefreshToken = jwtInfo.RefreshToken; - this.loginProfile.Token.CreatedTime = jwtInfo.CreatedTime; - storage.set(LOGIN_PROFILE_STORAGE_ID, JSON.stringify(this.loginProfile)); + + // 只改令牌,用户信息与权限清单必须沿用缓存里的原值。 + // pinia 不做持久化(刷新页面后 state 会重置成 new LoginProfile()), + // 如果直接 JSON.stringify(this.loginProfile) 写回,就会把缓存里的 + // Username / PermissionInfo 整份抹成空的:之后路由守卫按"空权限"判断, + // 表现为「F5 刷新过一次(触发了令牌刷新)之后,再导航就跳 403」。 + let profile: LoginProfile; + const cached = storage.get(LOGIN_PROFILE_STORAGE_ID); + if (cached) { + profile = JSON.parse(cached) as LoginProfile; + } else { + profile = this.loginProfile ?? new LoginProfile(); } + + if (profile?.Token) { + profile.Token.AccessToken = jwtInfo.AccessToken; + profile.Token.RefreshToken = jwtInfo.RefreshToken; + profile.Token.CreatedTime = jwtInfo.CreatedTime; + storage.set(LOGIN_PROFILE_STORAGE_ID, JSON.stringify(profile)); + } + + // 同步回内存:同页面后续读取(如 updateToken)才拿得到新令牌 + this.loginProfile = profile; }, getToken() { return storage.get(JWT_STORAGE_ID);