diff --git a/docs/superpowers/specs/2026-04-08-permission-system-enhancement-design.md b/docs/superpowers/specs/2026-04-08-permission-system-enhancement-design.md new file mode 100644 index 0000000..d01f56e --- /dev/null +++ b/docs/superpowers/specs/2026-04-08-permission-system-enhancement-design.md @@ -0,0 +1,538 @@ +# 权限系统增强设计文档 + +**日期**: 2026-04-08 +**作者**: 张翔 +**版本**: 1.0 +**状态**: 待审查 + +## 1. 概述 + +### 1.1 背景 + +当前系统已完成基础的路由权限控制,但存在以下优化空间: + +1. **菜单硬编码** - 菜单在前端硬编码,无法根据用户角色动态显示 +2. **权限数据分散** - 角色和权限信息存储在 localStorage,缺乏统一管理 +3. **缺少按钮级权限控制** - 无法控制按钮级别的权限 +4. **缺少 API 权限检查** - 前端调用 API 前未检查权限,可能发送无效请求 + +### 1.2 目标 + +实现完整的权限系统增强,包括: + +1. **动态菜单渲染** - 从后端获取菜单数据,根据用户权限动态渲染 +2. **权限缓存优化** - 使用 Pinia 统一管理权限数据,localStorage 持久化 +3. **权限指令** - 提供 `v-permission` 指令实现按钮级权限控制 +4. **API 权限检查** - 前端调用 API 前检查权限,减少无效请求 + +### 1.3 范围 + +**包含:** +- Permission Store (Pinia) +- v-permission 指令 +- 动态菜单渲染 +- API 权限检查工具 +- 相关单元测试 + +**不包含:** +- 后端权限系统修改(仅需新增 API) +- 数据库权限表结构调整 +- 其他业务功能开发 + +## 2. 架构设计 + +### 2.1 整体架构 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 前端应用 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ 路由守卫 │ │ 权限指令 │ │ 动态菜单 │ │ +│ │ (已完成) │ │ v-permission │ │ 渲染 │ │ +│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ +│ │ │ │ │ +│ └──────────────────┼──────────────────┘ │ +│ │ │ +│ ┌────────▼────────┐ │ +│ │ Permission │ │ +│ │ Store (Pinia) │ │ +│ └────────┬────────┘ │ +│ │ │ +│ ┌────────▼────────┐ │ +│ │ localStorage │ │ +│ │ (持久化) │ │ +│ └─────────────────┘ │ +│ │ +└───────────────────────────┬─────────────────────────────────┘ + │ + HTTP API │ + │ +┌───────────────────────────▼─────────────────────────────────┐ +│ 后端服务 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ /auth/login │ │ /menus/user │ │ /permissions │ │ +│ │ (已存在) │ │ (新增) │ │ (已存在) │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ RBAC 权限系统 (角色-权限-菜单) │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 2.2 数据流 + +``` +登录成功 + ↓ +解析 JWT token 获取角色 + ↓ +调用 fetchUserMenus() 获取菜单和权限 + ↓ +存入 Store + localStorage + ↓ +页面刷新时从 localStorage 恢复 +``` + +## 3. 详细设计 + +### 3.1 Permission Store + +**文件位置**: `src/stores/permission.ts` + +**状态定义**: + +```typescript +interface PermissionState { + roles: string[] // 用户角色 + permissions: string[] // 用户权限码 + menus: MenuItem[] // 用户菜单 + loaded: boolean // 是否已加载 +} + +interface MenuItem { + id: number + name: string + path: string + icon?: string + parentId?: number + sort: number + children?: MenuItem[] +} +``` + +**核心 Actions**: + +```typescript +// 初始化权限数据(从 localStorage 恢复) +initFromStorage(): void + +// 登录后设置权限数据 +setPermissionData(data: { + roles: string[] + permissions: string[] + menus: MenuItem[] +}): void + +// 从后端刷新权限数据 +async fetchUserMenus(): Promise + +// 清除权限数据(退出登录) +clearPermissionData(): void + +// 权限检查方法 +hasRole(role: string | string[]): boolean +hasPermission(permission: string | string[]): boolean +``` + +**持久化策略**: + +- 登录时:将角色、权限、菜单数据存入 localStorage +- 页面刷新:Pinia 从 localStorage 恢复数据,立即渲染菜单 +- 权限变更:提供刷新机制,同步更新 localStorage 和 Pinia +- 退出登录:清除所有数据 + +### 3.2 v-permission 指令 + +**文件位置**: `src/directives/permission.ts` + +**用法**: + +```vue + + + + + + + + + + + + +``` + +**实现逻辑**: + +```typescript +export const permissionDirective = { + mounted(el: HTMLElement, binding: DirectiveBinding) { + const permissionStore = usePermissionStore() + + const { arg, value } = binding + const checkType = arg || 'permission' // 默认权限检查 + + let hasAccess = false + + if (checkType === 'role') { + hasAccess = permissionStore.hasRole(value) + } else if (checkType === 'permission') { + hasAccess = permissionStore.hasPermission(value) + } + + if (!hasAccess) { + el.style.display = 'none' + } + } +} +``` + +**注册方式**: + +```typescript +// src/main.ts +import { permissionDirective } from '@/directives/permission' + +app.directive('permission', permissionDirective) +``` + +### 3.3 动态菜单渲染 + +**后端 API**: + +``` +GET /api/menus/user + +请求头: +Authorization: Bearer + +响应: +{ + "code": 200, + "data": { + "menus": [ + { + "id": 1, + "name": "仪表盘", + "path": "/dashboard", + "icon": "Odometer", + "parentId": null, + "sort": 1 + }, + { + "id": 2, + "name": "系统管理", + "path": "/system", + "icon": "Setting", + "parentId": null, + "sort": 2, + "children": [ + { + "id": 3, + "name": "用户管理", + "path": "/users", + "icon": null, + "parentId": 2, + "sort": 1 + } + ] + } + ], + "permissions": [ + "user:read", + "user:create", + "user:update", + "user:delete" + ] + } +} +``` + +**前端组件**: + +```vue + + + + +``` + +**递归菜单组件**: + +```vue + + +``` + +### 3.4 API 权限检查 + +**文件位置**: `src/utils/permission-check.ts` + +**权限映射配置**: + +```typescript +const apiPermissionMap: Record = { + '/api/users:GET': { permission: 'user:read', method: 'GET' }, + '/api/users:POST': { permission: 'user:create', method: 'POST' }, + '/api/users/*:PUT': { permission: 'user:update', method: 'PUT' }, + '/api/users/*:DELETE': { permission: 'user:delete', method: 'DELETE' }, + '/api/roles:GET': { permission: 'role:read', method: 'GET' }, + // ... 更多映射 +} +``` + +**检查函数**: + +```typescript +export function canAccessApi(path: string, method: string): boolean { + const permissionStore = usePermissionStore() + + const required = findRequiredPermission(path, method, apiPermissionMap) + + if (!required) { + return true // 未定义权限要求的 API 默认允许 + } + + return permissionStore.hasPermission(required.permission) +} +``` + +**集成到请求拦截器**: + +```typescript +// src/utils/request.ts +import { canAccessApi } from './permission-check' + +request.interceptors.request.use( + (config) => { + // 权限检查 + const path = config.url || '' + const method = config.method?.toUpperCase() || 'GET' + + if (!canAccessApi(path, method)) { + return Promise.reject(new Error('无权限访问此 API')) + } + + // 原有的 token 和签名逻辑 + // ... + + return config + } +) +``` + +## 4. 测试策略 + +### 4.1 测试覆盖范围 + +1. **Permission Store 单元测试** + - 测试权限数据的存储和恢复 + - 测试 hasRole 和 hasPermission 方法 + - 测试 localStorage 持久化 + - 测试数据清除功能 + +2. **v-permission 指令测试** + - 测试角色检查功能 + - 测试权限码检查功能 + - 测试数组参数处理 + - 测试元素隐藏/显示逻辑 + +3. **动态菜单测试** + - 测试菜单数据获取 + - 测试菜单树渲染 + - 测试菜单缓存机制 + - 测试菜单权限过滤 + +4. **API 权限检查测试** + - 测试权限映射匹配 + - 测试通配符匹配 + - 测试请求拦截逻辑 + +### 4.2 测试文件结构 + +``` +src/ +├── stores/ +│ └── __tests__/ +│ └── permission.test.ts +├── directives/ +│ └── __tests__/ +│ └── permission.test.ts +├── components/ +│ └── __tests__/ +│ └── MenuItem.test.ts +└── utils/ + └── __tests__/ + └── permission-check.test.ts +``` + +## 5. 实施计划 + +### 5.1 实施顺序 + +**第 1 步:Permission Store(1-2 小时)** +- 创建 `src/stores/permission.ts` +- 实现 localStorage 持久化 +- 编写单元测试 +- 集成到登录流程 + +**第 2 步:v-permission 指令(1-2 小时)** +- 创建 `src/directives/permission.ts` +- 注册全局指令 +- 编写单元测试 +- 在现有页面应用示例 + +**第 3 步:后端 API 开发(2-3 小时)** +- 新增 `GET /api/menus/user` 接口 +- 根据用户角色返回菜单树 +- 返回用户权限列表 +- 编写后端测试 + +**第 4 步:动态菜单渲染(2-3 小时)** +- 创建 `src/components/MenuItem.vue` +- 修改 `DefaultLayout.vue` +- 集成 Permission Store +- 编写组件测试 + +**第 5 步:API 权限检查(1-2 小时)** +- 创建 `src/utils/permission-check.ts` +- 集成到请求拦截器 +- 编写单元测试 +- 优化性能 + +### 5.2 后端 API 需求 + +**接口**: `GET /api/menus/user` + +**功能**: 获取当前登录用户可访问的菜单和权限 + +**业务逻辑**: +1. 从 token 获取用户 ID +2. 查询用户角色 +3. 根据角色查询菜单和权限 +4. 构建菜单树结构 +5. 返回菜单和权限列表 + +**预估时间**: 7-12 小时 + +## 6. 风险和约束 + +### 6.1 技术风险 + +1. **后端 API 开发时间** - 需要后端配合开发新 API +2. **菜单数据迁移** - 需要将硬编码菜单迁移到数据库 +3. **权限数据同步** - 前后端权限数据需要保持一致 + +### 6.2 约束条件 + +1. **向后兼容** - 需要兼容现有的路由守卫逻辑 +2. **性能要求** - 菜单加载不能影响页面首屏渲染速度 +3. **测试覆盖** - 所有新增代码需要单元测试覆盖 + +## 7. 验收标准 + +### 7.1 功能验收 + +- [ ] Permission Store 正确管理权限数据 +- [ ] v-permission 指令正确控制按钮显示 +- [ ] 动态菜单根据用户权限正确渲染 +- [ ] API 权限检查正确拦截无权限请求 + +### 7.2 质量验收 + +- [ ] 所有单元测试通过 +- [ ] 代码覆盖率 ≥ 80% +- [ ] TypeScript 类型检查通过 +- [ ] ESLint 检查通过 + +### 7.3 性能验收 + +- [ ] 菜单加载时间 < 500ms +- [ ] localStorage 读写不影响页面性能 +- [ ] 权限检查不影响 API 请求速度 + +## 8. 后续优化 + +### 8.1 短期优化 + +1. **权限缓存过期** - 添加权限数据过期机制 +2. **权限变更通知** - 实现权限变更后的实时通知 +3. **权限日志** - 记录权限检查日志,便于调试 + +### 8.2 长期优化 + +1. **权限可视化配置** - 提供权限配置界面 +2. **权限审计** - 记录用户权限变更历史 +3. **权限模板** - 提供常用权限模板,简化配置 + +## 9. 参考资料 + +- [Vue 3 官方文档](https://vuejs.org/) +- [Pinia 官方文档](https://pinia.vuejs.org/) +- [Element Plus 文档](https://element-plus.org/) +- [RBAC 权限模型](https://en.wikipedia.org/wiki/Role-based_access_control)