library-picturebook-activity/docs/MENU_PERMISSION_CONTROL.md

247 lines
6.7 KiB
Markdown
Raw Permalink Normal View History

2025-11-23 14:04:20 +08:00
# 菜单权限控制说明
## 📋 概述
系统通过 **权限编码Permission Code** 来控制用户对菜单的访问。菜单权限控制分为两个层面:
1. **菜单显示控制**:根据用户权限过滤菜单,只显示用户有权限访问的菜单
2. **路由访问控制**:通过路由守卫检查用户是否有权限访问某个页面
## 🔄 权限控制流程
```
用户登录
获取用户角色和权限
调用 /api/menus/user-menus 获取用户菜单
后端根据用户权限过滤菜单
前端动态生成路由和菜单
路由守卫检查页面访问权限
```
## 🎯 如何配置菜单权限
### 1. 创建权限
首先需要在权限管理中创建权限,例如:
- `menu:read` - 查看菜单权限
- `user:read` - 查看用户权限
- `role:read` - 查看角色权限
### 2. 将权限分配给角色
在角色管理中,为角色分配相应的权限。例如:
- **管理员角色**:拥有所有权限
- **普通用户角色**:只拥有 `user:read` 权限
### 3. 为用户分配角色
在用户管理中,为用户分配角色。用户会继承角色的所有权限。
### 4. 为菜单设置权限编码
在菜单管理中,为菜单设置 `权限编码` 字段:
#### 示例配置
| 菜单名称 | 路径 | 权限编码 | 说明 |
| -------- | ------------------- | ----------- | --------------------------------------------- |
| 用户管理 | /system/users | `user:read` | 只有拥有 `user:read` 权限的用户才能看到此菜单 |
| 角色管理 | /system/roles | `role:read` | 只有拥有 `role:read` 权限的用户才能看到此菜单 |
| 权限管理 | /system/permissions | - | 不设置权限编码,所有用户都可以看到 |
| 仪表盘 | /dashboard | - | 不设置权限编码,所有用户都可以看到 |
### 5. 权限编码规则
权限编码格式:`资源:操作`
常见示例:
- `user:read` - 查看用户
- `user:create` - 创建用户
- `user:update` - 更新用户
- `user:delete` - 删除用户
- `role:read` - 查看角色
- `menu:read` - 查看菜单
## 💻 技术实现
### 后端实现
#### 1. 菜单权限过滤(`MenusService.findUserMenus`
```typescript
// 获取用户的所有权限
const userPermissions = await this.authService.getUserPermissions(userId);
// 过滤菜单如果菜单有permission字段检查用户是否有该权限
const filterMenus = (menus: any[]): any[] => {
return menus
.filter((menu) => {
// 如果菜单没有设置权限要求,则显示
if (!menu.permission) {
return true;
}
// 如果设置了权限要求,检查用户是否有该权限
return userPermissions.includes(menu.permission);
})
.map((menu) => {
// 递归过滤子菜单
if (menu.children && menu.children.length > 0) {
menu.children = filterMenus(menu.children);
}
return menu;
});
};
```
#### 2. 用户权限获取(`AuthService.getUserPermissions`
```typescript
async getUserPermissions(userId: number): Promise<string[]> {
const user = await this.usersService.findOne(userId);
const permissions = new Set<string>();
// 遍历用户的所有角色
user.roles?.forEach((ur: any) => {
// 遍历角色的所有权限
ur.role.permissions?.forEach((rp: any) => {
permissions.add(rp.permission.code);
});
});
return Array.from(permissions);
}
```
### 前端实现
#### 1. 菜单转换为路由(`convertMenusToRoutes`
```typescript
const route: RouteRecordRaw = {
path: routePath,
name: routeName,
meta: {
title: menu.name,
requiresAuth: true,
// 如果菜单有权限要求添加到路由meta中
...(menu.permission && { permissions: [menu.permission] }),
},
component: componentLoader,
};
```
#### 2. 路由守卫检查(`router.beforeEach`
```typescript
// 检查权限
const requiredPermissions = to.meta.permissions;
if (requiredPermissions && requiredPermissions.length > 0) {
if (!authStore.hasAnyPermission(requiredPermissions)) {
// 没有所需权限,跳转到 403 页面
next({ name: "Forbidden" });
return;
}
}
```
#### 3. 权限检查方法(`authStore`
```typescript
// 检查是否有指定权限
const hasPermission = (permission: string): boolean => {
return user.value?.permissions?.includes(permission) ?? false;
};
// 检查是否有任一权限
const hasAnyPermission = (permissions: string[]): boolean => {
if (!permissions || permissions.length === 0) return true;
return permissions.some((perm) => hasPermission(perm));
};
```
## 📝 使用示例
### 示例 1创建需要权限的菜单
1. 登录系统,进入 **菜单管理**
2. 点击 **新增菜单**
3. 填写菜单信息:
- 菜单名称:`用户管理`
- 路由路径:`/system/users`
- 组件路径:`system/users/Index`
- **权限编码**`user:read` ⭐
- 父菜单:选择 `系统管理`
4. 保存菜单
### 示例 2创建公开菜单所有用户可见
1. 在菜单管理中新增菜单
2. **权限编码字段留空**
3. 这样所有用户都可以看到此菜单
### 示例 3为用户分配权限
1. 进入 **权限管理**,创建权限:
- 权限名称:`查看用户`
- 权限编码:`user:read`
- 资源:`user`
- 操作:`read`
2. 进入 **角色管理**,编辑角色:
- 为角色分配 `user:read` 权限
3. 进入 **用户管理**,编辑用户:
- 为用户分配该角色
## ⚠️ 注意事项
1. **权限编码必须唯一**:每个权限编码在系统中是唯一的
2. **菜单权限为空则公开**:如果菜单的 `权限编码` 字段为空,所有用户都可以看到
3. **子菜单继承父菜单权限**:子菜单会独立检查权限,不会自动继承父菜单权限
4. **路由和菜单双重控制**
- 菜单显示控制:控制菜单是否在侧边栏显示
- 路由访问控制:控制用户是否可以直接访问页面(通过 URL
5. **权限变更后需重新登录**:权限变更后,用户需要重新登录才能看到新的菜单
## 🔍 调试技巧
### 1. 查看用户权限
在浏览器控制台执行:
```javascript
// 查看当前用户权限
console.log(useAuthStore().user?.permissions);
// 检查是否有特定权限
console.log(useAuthStore().hasPermission("user:read"));
```
### 2. 查看用户菜单
```javascript
// 查看当前用户的菜单
console.log(useAuthStore().menus);
```
### 3. 后端调试
在后端日志中查看:
- 用户权限列表
- 菜单过滤结果
## 📚 相关文档
- [RBAC 权限控制详解](./RBAC_GUIDE.md)
- [菜单管理使用说明](./MENU_MANAGEMENT.md)
- [权限管理使用说明](./PERMISSION_MANAGEMENT.md)