修复:原来的统一去了404, 现在加了403, 和部分bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 6m54s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 6m54s
This commit is contained in:
@@ -110,14 +110,22 @@ async function handleRouteGuard(
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试刷新路由重新注册
|
||||
// 路由未匹配时,判断是 404 还是 403
|
||||
if (userStore.isLogin) {
|
||||
isRouteRegistered.value = false
|
||||
await handleDynamicRoutes(to, router, next)
|
||||
return
|
||||
// 检查路由是否存在于 asyncRoutes 中
|
||||
const routeExistsInAsync = checkRouteExistsInAsyncRoutes(to.path, asyncRoutes)
|
||||
console.log(`[路由检查] 目标路径: ${to.path}, 是否存在于asyncRoutes: ${routeExistsInAsync}`)
|
||||
|
||||
if (routeExistsInAsync) {
|
||||
// 路由存在于 asyncRoutes 但未注册,说明用户没有权限
|
||||
console.warn('路由存在但用户无权限访问:', to.path)
|
||||
next(RoutesAlias.Exception403 || '/exception/403')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 如果以上都不匹配,跳转到404
|
||||
// 路由不存在,跳转到 404
|
||||
console.log(`[路由检查] 路径 ${to.path} 不存在于asyncRoutes,跳转404`)
|
||||
next(RoutesAlias.Exception404)
|
||||
}
|
||||
|
||||
@@ -374,7 +382,7 @@ function convertBackendMenuToRoute(
|
||||
}
|
||||
}
|
||||
|
||||
// 递归处理所有层级的 children
|
||||
// 递归处理后端返回的 children
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
const children = menu.children
|
||||
.map((child: any) => convertBackendMenuToRoute(child, routeMap, menuUrl))
|
||||
@@ -453,6 +461,88 @@ function isValidMenuList(menuList: AppRouteRecord[]): boolean {
|
||||
return Array.isArray(menuList) && menuList.length > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路由是否存在于 asyncRoutes 中
|
||||
* 支持动态参数匹配,如 /account-management/enterprise-customer/customer-accounts/3000 匹配 enterprise-customer/customer-accounts/:id
|
||||
* @param targetPath 目标路由路径,如 /account-management/enterprise-customer/customer-accounts/3000
|
||||
* @param routes 路由配置数组
|
||||
* @param parentPath 父路由路径
|
||||
*/
|
||||
function checkRouteExistsInAsyncRoutes(
|
||||
targetPath: string,
|
||||
routes: AppRouteRecord[],
|
||||
parentPath = ''
|
||||
): boolean {
|
||||
for (const route of routes) {
|
||||
// 构建完整路径
|
||||
const fullPath = route.path.startsWith('/')
|
||||
? route.path
|
||||
: parentPath
|
||||
? `${parentPath}/${route.path}`.replace(/\/+/g, '/')
|
||||
: `/${route.path}`
|
||||
|
||||
// 检查当前路由是否匹配(支持动态参数)
|
||||
const isMatch = matchRoutePath(targetPath, fullPath)
|
||||
|
||||
if (isMatch) {
|
||||
console.log(`[路由匹配成功] 目标: ${targetPath}, 匹配到: ${fullPath}`)
|
||||
return true
|
||||
}
|
||||
|
||||
// 递归检查子路由
|
||||
if (route.children && route.children.length > 0) {
|
||||
if (checkRouteExistsInAsyncRoutes(targetPath, route.children, fullPath)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配路由路径,支持动态参数
|
||||
* @param targetPath 实际路径,如 /account-management/enterprise-customer/customer-accounts/3000
|
||||
* @param routePath 路由定义路径,如 /account-management/enterprise-customer/customer-accounts/:id
|
||||
*/
|
||||
function matchRoutePath(targetPath: string, routePath: string): boolean {
|
||||
// 移除查询参数
|
||||
const cleanTargetPath = targetPath.split('?')[0]
|
||||
const cleanRoutePath = routePath.split('?')[0]
|
||||
|
||||
// 如果完全匹配,直接返回
|
||||
if (cleanTargetPath === cleanRoutePath) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 将路径分割成段
|
||||
const targetSegments = cleanTargetPath.split('/').filter(Boolean)
|
||||
const routeSegments = cleanRoutePath.split('/').filter(Boolean)
|
||||
|
||||
// 段数必须相同
|
||||
if (targetSegments.length !== routeSegments.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 逐段比较
|
||||
for (let i = 0; i < routeSegments.length; i++) {
|
||||
const routeSegment = routeSegments[i]
|
||||
const targetSegment = targetSegments[i]
|
||||
|
||||
// 如果是动态参数(以 : 开头),跳过比较
|
||||
if (routeSegment.startsWith(':')) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果不是动态参数,必须完全匹配
|
||||
if (routeSegment !== targetSegment) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置路由相关状态
|
||||
*/
|
||||
|
||||
@@ -107,10 +107,12 @@ export const hasRoutePermission = (
|
||||
*/
|
||||
function checkMenuAccess(path: string, menus: any[]): boolean {
|
||||
for (const menu of menus) {
|
||||
// 检查当前菜单的 URL 是否匹配
|
||||
if (menu.url && (path === menu.url || path.startsWith(menu.url + '/'))) {
|
||||
// 检查当前菜单的 URL 是否匹配(支持动态参数)
|
||||
if (menu.url && matchMenuPath(path, menu.url)) {
|
||||
console.log(`[菜单权限检查] 路径 ${path} 匹配菜单 ${menu.url}`)
|
||||
return true
|
||||
}
|
||||
|
||||
// 递归检查子菜单
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
if (checkMenuAccess(path, menu.children)) {
|
||||
@@ -118,9 +120,53 @@ function checkMenuAccess(path: string, menus: any[]): boolean {
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`[菜单权限检查] 路径 ${path} 未找到匹配的菜单`)
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配菜单路径,支持动态参数
|
||||
* @param actualPath 实际访问路径,如 /account-management/enterprise-customer/customer-accounts/3000
|
||||
* @param menuPath 菜单定义路径,如 /account-management/enterprise-customer/customer-accounts/:id
|
||||
*/
|
||||
function matchMenuPath(actualPath: string, menuPath: string): boolean {
|
||||
// 移除查询参数
|
||||
const cleanActualPath = actualPath.split('?')[0]
|
||||
const cleanMenuPath = menuPath.split('?')[0]
|
||||
|
||||
// 如果完全匹配,直接返回
|
||||
if (cleanActualPath === cleanMenuPath) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 将路径分割成段
|
||||
const actualSegments = cleanActualPath.split('/').filter(Boolean)
|
||||
const menuSegments = cleanMenuPath.split('/').filter(Boolean)
|
||||
|
||||
// 段数必须相同
|
||||
if (actualSegments.length !== menuSegments.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 逐段比较
|
||||
for (let i = 0; i < menuSegments.length; i++) {
|
||||
const menuSegment = menuSegments[i]
|
||||
const actualSegment = actualSegments[i]
|
||||
|
||||
// 如果是动态参数(以 : 开头),跳过比较
|
||||
if (menuSegment.startsWith(':')) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果不是动态参数,必须完全匹配
|
||||
if (menuSegment !== actualSegment) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 Token 是否有效
|
||||
* 简单检查,真实项目中应该验证 JWT 或者调用后端接口
|
||||
|
||||
Reference in New Issue
Block a user