feat(rbac): F3 前端 RBAC 按钮级控制

后端:
- 新增 GET /user/permissions 端点返回当前用户权限码
- Login 响应附带 permissions 数组
- collectUserPermissionCodes 用 raw SQL JOIN 避免 GORM many2many 表名问题
- admin 用户返回 ['*'] 通配符

前端:
- usePermission hook (hasPermission/hasAnyPermission/hasAllPermissions)
- <HasPermission> 组件 (permission/anyOf/allOf + fallback)
- zustand store 新增 permissions 字段
- Sidebar 菜单递归过滤 (42 菜单项全部标注 permission)
- ServerManager: 添加/导入/批量删除按钮按权限显隐
- ServerTableRow: 终端/编辑/文件/删除按权限显隐
- SystemUserTab: 新建/导入/编辑/删除按钮按权限显隐
- MainLayout: 页面刷新自动拉取权限
- Login: 登录时存储 permissions

验证:
- admin: permissions=['*'] 通配符
- viewer: 7 个只读权限 (dashboard:view/server:view/...)
- viewer 无 server:create/delete
- 10/10 回归测试通过
- npm run build 零错误
This commit is contained in:
attacker committed 2026-06-25 22:51:25 +08:00
1 parent 77c234b060
commit be2a377f01
30 files changed
+2328 -462

No files matched your search

+12 -8
View File
@@ -125,19 +125,23 @@ services/api.ts (1324L)
- [x] 导出限制 10000 条防内存溢出
- [x] JSON 格式向后兼容(format=json)
### F3: 前端 RBAC 按钮级控制 [pending]
### F3: 前端 RBAC 按钮级控制 [done]
**问题**: 后端 RBAC 完善,但前端无按钮级权限控制
**方案**:
- 封装 `<HasPermission permission="xxx">` 组件
- Sidebar 菜单按角色过滤
- 操作按钮根据权限显示/隐藏
- 后端新增 `GET /user/permissions` 端点返回当前用户权限码;Login 响应附带 `permissions` 数组
- 封装 `<HasPermission permission="xxx">` 组件 + `usePermission()` hook
- Sidebar 菜单按权限过滤(每个菜单项带 `permission` 字段)
- 服务器管理/系统管理等关键页面的增删改按钮按权限显隐
- admin 用户 permissions=`["*"]` 通配符,所有按钮可见
**验收标准**:
- [ ] 不同角色看到不同菜单
- [ ] 无权限按钮自动隐藏
- [ ] 权限变更后实时生效
- [x] 不同角色看到不同菜单(viewer 只看到 7 个只读菜单,admin 看到全部)
- [x] 无权限按钮自动隐藏(viewer 看不到「添加服务器」「删除」按钮)
- [x] 权限变更后实时生效(登录即获取最新权限,刷新页面自动拉取)
- [x] admin 通配符 `["*"]` 短路逻辑
- [x] 页面刷新后自动拉取权限(MainLayout useEffect)
---
@@ -192,7 +196,7 @@ services/api.ts (1324L)
| Q3 | api.ts 拆分 | P0 | **done** |
| F1 | 告警静默规则 | P1 | **done** |
| F2 | 审计日志导出 | P1 | **done** |
| F3 | 前端 RBAC 控制 | P1 | pending |
| F3 | 前端 RBAC 控制 | P1 | **done** |
| A1 | K8s 路由统一 | P2 | pending |
| A2 | 告警引擎分布式 | P2 | pending |
| A3 | WebSocket 管理 | P2 | pending |