权限调试指南
常见问题
1. 菜单不显示
可能原因:
- 用户没有菜单权限
- 菜单被禁用
- 路由配置错误
- 菜单类型不正确
排查步骤:
typescript
// 1. 检查用户权限
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
console.log('用户权限:', userStore.permissions)
console.log('用户角色:', userStore.roles)
// 2. 检查菜单数据
const menuStore = usePermissionStore()
console.log('菜单路由:', menuStore.routes)
// 3. 检查后端返回的菜单
// 在浏览器 Network 标签查看 GET /api/v1/menus/routes 响应1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
解决方案:
sql
-- 检查菜单是否启用
SELECT * FROM sys_menu WHERE status = 1;
-- 检查用户角色
SELECT * FROM sys_user_role WHERE user_id = ?;
-- 检查角色菜单
SELECT * FROM sys_role_menu WHERE role_id = ?;1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2. 按钮不显示
可能原因:
- 用户没有按钮权限
- 权限标识配置错误
v-hasPerm指令使用错误
排查步骤:
typescript
// 1. 检查权限标识
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
console.log('用户权限列表:', userStore.permissions)
// 2. 检查按钮权限标识
// 如 v-hasPerm="['sys:user:add']"
// 确认 'sys:user:add' 在 userStore.permissions 中1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
解决方案:
vue
<!-- 临时调试:显示所有按钮 -->
<el-button v-if="true">新增</el-button>
<!-- 正确方式 -->
<el-button v-hasPerm="['sys:user:add']">新增</el-button>1
2
3
4
5
2
3
4
5
3. 接口返回 403
可能原因:
- Token 失效
- 权限不足
- 接口权限配置错误
排查步骤:
typescript
// 1. 检查 Token
const token = localStorage.getItem('accessToken')
console.log('Token:', token)
// 2. 解析 Token(使用 jwt.io)
// 查看过期时间和用户信息
// 3. 检查请求头
// Network 标签 → Request Headers → Authorization1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
解决方案:
java
// 后端检查权限
@PreAuthorize("hasPermission('sys:user:list')")
public List<User> list() {
// ...
}
// 确保 Token 有效且用户有对应权限1
2
3
4
5
6
7
2
3
4
5
6
7
4. 动态路由不生效
可能原因:
- 路由守卫逻辑错误
- 路由格式不正确
router.addRoute调用时机错误
排查步骤:
typescript
// src/permission.ts
router.beforeEach(async (to, from, next) => {
// 1. 打印路由信息
console.log('目标路由:', to)
console.log('已注册路由:', router.getRoutes().map(r => r.path))
// 2. 检查是否已加载路由
if (!permissionStore.isRoutesLoaded) {
// 加载路由
const routes = await permissionStore.generateRoutes()
routes.forEach(route => {
router.addRoute(route)
})
next({ ...to, replace: true })
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
解决方案:
typescript
// 确保路由格式正确
const route = {
path: '/system/user',
name: 'SystemUser',
component: () => import('@/views/system/user/index.vue'),
meta: {
title: '用户管理',
icon: 'user',
permissions: ['sys:user:list']
}
}
// 使用 router.addRoute
router.addRoute(route)1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
调试工具
1. 浏览器 DevTools
Application → Local Storage:
accessToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
refreshToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...1
2
2
Vue DevTools:
- 检查 Pinia Store 状态
- 检查组件权限指令
2. 后端日志
启用权限日志:
yaml
# application.yml
logging:
level:
com.youlai.auth: DEBUG
org.springframework.security: DEBUG1
2
3
4
5
2
3
4
5
查看日志:
log
2024-01-15 10:30:00 DEBUG [AuthorizationFilter] - Checking permission: sys:user:list
2024-01-15 10:30:00 DEBUG [AuthorizationFilter] - User permissions: [sys:user:list, sys:user:add]
2024-01-15 10:30:00 DEBUG [AuthorizationFilter] - Permission granted1
2
3
2
3
3. 数据库查询
sql
-- 查询用户权限
SELECT
u.username,
r.role_name,
m.permission
FROM sys_user u
JOIN sys_user_role ur ON u.id = ur.user_id
JOIN sys_role r ON ur.role_id = r.id
JOIN sys_role_menu rm ON r.id = rm.role_id
JOIN sys_menu m ON rm.menu_id = m.id
WHERE u.username = 'admin';
-- 查询菜单树
SELECT
id,
parent_id,
name,
path,
permission
FROM sys_menu
WHERE status = 1
ORDER BY sort;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
权限配置检查清单
前端检查
- [ ] Token 是否正确存储
- [ ] 请求头是否携带 Authorization
- [ ] 权限指令是否正确使用
- [ ] 路由守卫逻辑是否正确
后端检查
- [ ] 用户是否有对应角色
- [ ] 角色是否有对应菜单权限
- [ ] 菜单权限标识是否正确
- [ ] 接口是否添加权限注解
数据库检查
- [ ]
sys_user_role表数据是否正确 - [ ]
sys_role_menu表数据是否正确 - [ ]
sys_menu表菜单是否启用 - [ ] 权限标识是否唯一
常见错误示例
错误 1:权限标识不一致
前端:
vue
<el-button v-hasPerm="['sys:user:add']">新增</el-button>1
后端:
java
@PreAuthorize("hasPermission('sys:user:create')") // 不一致
public void add() {}1
2
2
解决:统一使用 sys:user:add
错误 2:菜单类型配置错误
sql
-- 按钮类型菜单的 parent_id 应该指向父菜单
INSERT INTO sys_menu (name, type, parent_id, permission)
VALUES ('新增用户', 3, 1, 'sys:user:add');
-- ↑ ↑
-- 按钮类型 父菜单 ID1
2
3
4
5
2
3
4
5
错误 3:超级管理员判断错误
typescript
// 错误:硬编码角色名称
if (userStore.roles.includes('admin')) {
// ...
}
// 正确:使用角色标识
if (userStore.roles.includes('ADMIN')) {
// ...
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
临时解决方案
如果权限系统有问题,可以临时禁用:
typescript
// src/utils/permission.ts
export function checkPermission(permissions: string[]): boolean {
// 临时:返回 true
return true
// 原逻辑
// return permissions.some(p => userStore.permissions.includes(p))
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
⚠️ 注意:生产环境必须启用权限控制!
