fix(router): validate server session before loading routes

This commit is contained in:
Kroytz committed 2026-07-19 00:32:14 +08:00
1 parent 17b2ba49a8
commit 6ffdbcb3d7
7 files changed
+40 -54

No files matched your search

+2 -3
View File
@@ -9,7 +9,7 @@ import axios, {
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus' import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
import qs from 'qs' import qs from 'qs'
import { config } from '@/config/axios/config' import { config } from '@/config/axios/config'
import { getTenantId, removeAuthenticated } from '@/utils/auth' import { getTenantId } from '@/utils/auth'
import errorCode from './errorCode' import errorCode from './errorCode'
import { resetRouter } from '@/router' import { resetRouter } from '@/router'
@@ -201,9 +201,8 @@ const handleAuthorized = () => {
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
resetRouter() // 重置静态路由表 resetRouter() // 重置静态路由表
removeAuthenticated()
isRelogin.show = false isRelogin.show = false
// 干掉token后再走一次路由让它过router.beforeEach的校验 // 重新加载后由路由守卫向服务端确认会话
window.location.href = window.location.href window.location.href = window.location.href
}) })
} }
+37 -34
View File
@@ -1,7 +1,6 @@
import router from './router' import router, { resetRouter } from './router'
import type { RouteRecordRaw } from 'vue-router' import type { RouteRecordRaw } from 'vue-router'
import { isRelogin } from '@/config/axios/service' import { isRelogin } from '@/config/axios/service'
import { isAuthenticated } from '@/utils/auth'
import { useTitle } from '@/hooks/web/useTitle' import { useTitle } from '@/hooks/web/useTitle'
import { useNProgress } from '@/hooks/web/useNProgress' import { useNProgress } from '@/hooks/web/useNProgress'
import { usePageLoading } from '@/hooks/web/usePageLoading' import { usePageLoading } from '@/hooks/web/usePageLoading'
@@ -60,42 +59,46 @@ const whiteList = [
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
start() start()
loadStart() loadStart()
if (isAuthenticated()) { const userStore = useUserStoreWithOut()
if (to.path === '/login') { if (whiteList.includes(to.path)) {
if (to.path === '/login' && userStore.getIsSetUser) {
next({ path: '/' }) next({ path: '/' })
} else { } else {
// 获取所有字典
const dictStore = useDictStoreWithOut()
const userStore = useUserStoreWithOut()
const permissionStore = usePermissionStoreWithOut()
if (!dictStore.getIsSetDict) {
await dictStore.setDictMap()
}
if (!userStore.getIsSetUser) {
isRelogin.show = true
await userStore.setUserInfoAction()
isRelogin.show = false
// 后端过滤菜单
await permissionStore.generateRoutes(userStore.getMenus)
permissionStore.getAddRouters.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw) // 动态添加可访问路由表
})
const redirectPath = from.query.redirect || to.path
// 修复跳转时不带参数的问题
const redirect = decodeURIComponent(redirectPath as string)
const { basePath, paramsObject: query } = parseURL(redirect)
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect, query }
next(nextData)
} else {
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next() next()
} else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
} }
return
}
if (userStore.getIsSetUser) {
next()
return
}
isRelogin.show = true
try {
await userStore.setUserInfoAction()
const dictStore = useDictStoreWithOut()
if (!dictStore.getIsSetDict) {
await dictStore.setDictMap()
}
const permissionStore = usePermissionStoreWithOut()
await permissionStore.generateRoutes(userStore.getMenus)
permissionStore.getAddRouters.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw)
})
const redirectPath = from.query.redirect || to.path
const redirect = decodeURIComponent(redirectPath as string)
const { paramsObject: query } = parseURL(redirect)
next(to.path === redirect ? { ...to, replace: true } : { path: redirect, query })
} catch {
userStore.resetState()
resetRouter()
next(`/login?redirect=${encodeURIComponent(to.fullPath)}`)
} finally {
isRelogin.show = false
} }
}) })
@@ -1,6 +1,5 @@
import { store } from '@/store' import { store } from '@/store'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { isAuthenticated, removeAuthenticated } from '@/utils/auth'
import { getInfo, loginOut } from '@/api/login' import { getInfo, loginOut } from '@/api/login'
interface UserVO { interface UserVO {
@@ -51,10 +50,6 @@ export const useUserStore = defineStore('admin-user', {
}, },
actions: { actions: {
async setUserInfoAction() { async setUserInfoAction() {
if (!isAuthenticated()) {
this.resetState()
return null
}
const userInfo = await getInfo() const userInfo = await getInfo()
this.permissions = userInfo.permissions this.permissions = userInfo.permissions
this.roles = userInfo.roles this.roles = userInfo.roles
@@ -72,7 +67,6 @@ export const useUserStore = defineStore('admin-user', {
try { try {
await loginOut() await loginOut()
} finally { } finally {
removeAuthenticated()
this.resetState() this.resetState()
} }
}, },
-6
View File
@@ -1,18 +1,12 @@
import { useCache, CACHE_KEY } from '@/hooks/web/useCache' import { useCache, CACHE_KEY } from '@/hooks/web/useCache'
const { wsCache } = useCache() const { wsCache } = useCache()
const { wsCache: sessionCache } = useCache('sessionStorage')
wsCache.delete('ACCESS_TOKEN') wsCache.delete('ACCESS_TOKEN')
wsCache.delete('REFRESH_TOKEN') wsCache.delete('REFRESH_TOKEN')
wsCache.delete('user') wsCache.delete('user')
wsCache.delete('roleRouters') wsCache.delete('roleRouters')
const AuthenticatedKey = 'AUTHENTICATED'
export const isAuthenticated = () => sessionCache.get(AuthenticatedKey) === true
export const setAuthenticated = () => sessionCache.set(AuthenticatedKey, true)
export const removeAuthenticated = () => sessionCache.delete(AuthenticatedKey)
// ========== 账号相关 ========== // ========== 账号相关 ==========
export type LoginFormType = { export type LoginFormType = {
@@ -252,7 +252,6 @@ const tryLogin = async () => {
const state = route?.query?.state as string const state = route?.query?.state as string
await LoginApi.socialLogin(type, code, state) await LoginApi.socialLogin(type, code, state)
authUtil.setAuthenticated()
router.push({ path: redirect || '/' }) router.push({ path: redirect || '/' })
} catch (err) {} } catch (err) {}
@@ -297,7 +296,6 @@ const handleLogin = async (params) => {
} else { } else {
authUtil.removeLoginForm() authUtil.removeLoginForm()
} }
authUtil.setAuthenticated()
if (!redirect) { if (!redirect) {
redirect = '/' redirect = '/'
} }
@@ -186,7 +186,6 @@ const handleLogin = async (params) => {
} else { } else {
authUtil.removeLoginForm() authUtil.removeLoginForm()
} }
authUtil.setAuthenticated()
if (!redirect.value) { if (!redirect.value) {
redirect.value = '/' redirect.value = '/'
} }
@@ -97,7 +97,7 @@ import type { RouteLocationNormalizedLoaded } from 'vue-router'
import { useIcon } from '@/hooks/web/useIcon' import { useIcon } from '@/hooks/web/useIcon'
import { setTenantId, setAuthenticated } from '@/utils/auth' import { setTenantId } from '@/utils/auth'
import { usePermissionStore } from '@/store/modules/permission' import { usePermissionStore } from '@/store/modules/permission'
import { getTenantIdByName, sendSmsCode, smsLogin } from '@/api/login' import { getTenantIdByName, sendSmsCode, smsLogin } from '@/api/login'
import LoginFormTitle from './LoginFormTitle.vue' import LoginFormTitle from './LoginFormTitle.vue'
@@ -196,7 +196,6 @@ const signIn = async () => {
smsVO.loginSms.code = loginData.loginForm.code smsVO.loginSms.code = loginData.loginForm.code
await smsLogin(smsVO.loginSms) await smsLogin(smsVO.loginSms)
.then(async () => { .then(async () => {
setAuthenticated()
if (!redirect.value) { if (!redirect.value) {
redirect.value = '/' redirect.value = '/'
} }