fix(router): validate server session before loading routes
This commit is contained in:
1 parent
17b2ba49a8
commit
6ffdbcb3d7
7 files changed
+33
-47
No files matched your search
@@ -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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
// 获取所有字典
|
next()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userStore.getIsSetUser) {
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isRelogin.show = true
|
||||||
|
try {
|
||||||
|
await userStore.setUserInfoAction()
|
||||||
|
|
||||||
const dictStore = useDictStoreWithOut()
|
const dictStore = useDictStoreWithOut()
|
||||||
const userStore = useUserStoreWithOut()
|
|
||||||
const permissionStore = usePermissionStoreWithOut()
|
|
||||||
if (!dictStore.getIsSetDict) {
|
if (!dictStore.getIsSetDict) {
|
||||||
await dictStore.setDictMap()
|
await dictStore.setDictMap()
|
||||||
}
|
}
|
||||||
if (!userStore.getIsSetUser) {
|
|
||||||
isRelogin.show = true
|
const permissionStore = usePermissionStoreWithOut()
|
||||||
await userStore.setUserInfoAction()
|
|
||||||
isRelogin.show = false
|
|
||||||
// 后端过滤菜单
|
|
||||||
await permissionStore.generateRoutes(userStore.getMenus)
|
await permissionStore.generateRoutes(userStore.getMenus)
|
||||||
permissionStore.getAddRouters.forEach((route) => {
|
permissionStore.getAddRouters.forEach((route) => {
|
||||||
router.addRoute(route as unknown as RouteRecordRaw) // 动态添加可访问路由表
|
router.addRoute(route as unknown as RouteRecordRaw)
|
||||||
})
|
})
|
||||||
|
|
||||||
const redirectPath = from.query.redirect || to.path
|
const redirectPath = from.query.redirect || to.path
|
||||||
// 修复跳转时不带参数的问题
|
|
||||||
const redirect = decodeURIComponent(redirectPath as string)
|
const redirect = decodeURIComponent(redirectPath as string)
|
||||||
const { basePath, paramsObject: query } = parseURL(redirect)
|
const { paramsObject: query } = parseURL(redirect)
|
||||||
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect, query }
|
next(to.path === redirect ? { ...to, replace: true } : { path: redirect, query })
|
||||||
next(nextData)
|
} catch {
|
||||||
} else {
|
userStore.resetState()
|
||||||
next()
|
resetRouter()
|
||||||
}
|
next(`/login?redirect=${encodeURIComponent(to.fullPath)}`)
|
||||||
}
|
} finally {
|
||||||
} else {
|
isRelogin.show = false
|
||||||
if (whiteList.indexOf(to.path) !== -1) {
|
|
||||||
next()
|
|
||||||
} else {
|
|
||||||
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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 = '/'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user