# Nova Admin 权限系统文档 ## 概述 Nova Admin 采用基于角色的访问控制(RBAC)模型,通过用户角色和权限指令实现细粒度的权限控制。系统支持路由级别和组件级别的权限验证。 ## 🏗️ 权限架构 ### 核心组件 1. **权限Hook** (`src/hooks/usePermission.ts`) 2. **权限指令** (`src/directives/permission.ts`) 3. **路由权限过滤** (`src/store/router/helper.ts`) 4. **用户角色管理** (`src/store/auth.ts`) ## 🎭 角色系统 ### 角色类型定义 ```typescript type Entity.RoleType = string // 如: 'admin', 'user', 'super', 'editor' ``` ### 内置角色层级 1. **super**: 超级管理员,拥有所有权限 2. **admin**: 管理员角色 3. **user**: 普通用户角色 4. **editor**: 编辑者角色 ### 角色权限矩阵 | 功能模块 | super | admin | editor | user | |---------|-------|-------|--------|------| | 仪表盘 | ✅ | ✅ | ✅ | ✅ | | 用户管理 | ✅ | ✅ | ❌ | ❌ | | 系统设置 | ✅ | ✅ | ❌ | ❌ | | 内容编辑 | ✅ | ✅ | ✅ | ❌ | ## 🔐 权限验证机制 ### 1. usePermission Hook 位置:`src/hooks/usePermission.ts` #### 核心逻辑 ```typescript function hasPermission(permission?: Entity.RoleType | Entity.RoleType[]) { if (!permission) return true // 无权限要求,直接通过 if (!authStore.userInfo) return false // 未登录,拒绝访问 const { role } = authStore.userInfo // super 角色拥有所有权限 let has = role.includes('super') if (!has) { if (isArray(permission)) { // 权限为数组,判断是否有交集 has = permission.some(i => role.includes(i)) } if (isString(permission)) { // 权限为字符串,判断是否包含 has = role.includes(permission) } } return has } ``` #### 使用方式 ```typescript import { usePermission } from '@/hooks' const { hasPermission } = usePermission() // 检查单个角色 if (hasPermission('admin')) { // 用户拥有 admin 角色 } // 检查多个角色(任一匹配) if (hasPermission(['admin', 'editor'])) { // 用户拥有 admin 或 editor 角色 } ``` ### 2. 权限指令 位置:`src/directives/permission.ts` #### 指令实现 ```typescript const permissionDirective: Directive = { mounted(el, binding) { updatapermission(el, binding.value) }, updated(el, binding) { updatapermission(el, binding.value) }, } function updatapermission(el: HTMLElement, permission: Entity.RoleType | Entity.RoleType[]) { if (!permission) { throw new Error('v-permission Directive with no explicit role attached') } if (!hasPermission(permission)) { el.parentElement?.removeChild(el) // 移除DOM元素 } } ``` #### 使用方式 ```vue ``` ## 🛣️ 路由权限控制 ### 路由元信息配置 ```typescript interface AppRoute.RowRoute { // ... 其他属性 roles?: Entity.RoleType[] // 访问路由所需的角色 requiresAuth?: boolean // 是否需要登录 } ``` ### 权限路由示例 ```typescript export const staticRoutes: AppRoute.RowRoute[] = [ { name: 'userManagement', path: '/setting/account', title: '用户管理', requiresAuth: true, roles: ['super', 'admin'], // 只有 super 或 admin 可访问 componentPath: '/setting/account/index.vue', }, { name: 'superOnly', path: '/admin/super', title: '超级管理', requiresAuth: true, roles: ['super'], // 只有 super 可访问 componentPath: '/admin/super/index.vue', } ] ``` ### 路由权限过滤 在 `src/store/router/helper.ts` 中实现: ```typescript export function createRoutes(routes: AppRoute.RowRoute[]) { const { hasPermission } = usePermission() // 权限过滤 let resultRouter = standardizedRoutes(routes) resultRouter = resultRouter.filter(i => hasPermission(i.meta.roles)) // ... 其他处理 return resultRouter } ``` ## 📋 权限验证流程 ### 1. 路由级权限验证 ```mermaid flowchart TD A[用户访问路由] --> B{路由需要权限?} B -->|否| G[允许访问] B -->|是| C{用户已登录?} C -->|否| D[重定向到登录页] C -->|是| E{用户角色匹配?} E -->|否| F[显示403错误] E -->|是| G[允许访问] ``` ### 2. 组件级权限验证 ```mermaid flowchart TD A[组件渲染] --> B{使用了权限指令?} B -->|否| F[正常渲染] B -->|是| C{用户角色匹配?} C -->|否| D[移除DOM元素] C -->|是| E[正常显示元素] ``` ### 3. API级权限验证 ```mermaid flowchart TD A[调用API] --> B[请求携带Token] B --> C[后端验证Token] C --> D{Token有效?} D -->|否| E[返回401错误] D -->|是| F{用户权限足够?} F -->|否| G[返回403错误] F -->|是| H[返回数据] ``` ## 🛠️ 开发指南 ### 1. 添加新角色 1. **定义角色类型**(如果使用TypeScript): ```typescript type Entity.RoleType = 'super' | 'admin' | 'editor' | 'user' | 'newRole' ``` 2. **在用户信息中配置角色**: ```typescript const userInfo = { id: 1, userName: 'testUser', role: ['newRole'], // 用户角色数组 // ... 其他信息 } ``` 3. **在路由中使用新角色**: ```typescript { name: 'newFeature', path: '/new-feature', roles: ['newRole'], // 新角色权限 // ... 其他配置 } ``` ### 2. 组件中权限检查 ```vue ``` ### 3. 动态权限控制 ```typescript // 动态检查权限 function checkDynamicPermission(action: string) { const requiredRoles = getRequiredRolesForAction(action) return hasPermission(requiredRoles) } // 根据权限显示菜单 const visibleMenuItems = computed(() => { return menuItems.filter(item => hasPermission(item.requiredRoles)) }) ``` ## 🔧 配置选项 ### 权限配置文件 可以创建权限配置文件来集中管理权限: ```typescript // src/config/permissions.ts export const PERMISSIONS = { USER_MANAGEMENT: ['super', 'admin'], CONTENT_EDIT: ['super', 'admin', 'editor'], VIEW_DASHBOARD: ['super', 'admin', 'editor', 'user'], SYSTEM_CONFIG: ['super'], } as const // 使用配置 hasPermission(PERMISSIONS.USER_MANAGEMENT) ``` ### 默认权限行为 ```typescript // 默认情况下的权限行为 const defaultPermissionBehavior = { // 未指定权限时的默认行为 noPermissionRequired: true, // 超级管理员绕过所有权限检查 superAdminBypass: true, // 权限检查失败时的行为 onPermissionDenied: 'hide', // 'hide' | 'disable' | 'redirect' } ``` ## 🚨 最佳实践 ### 1. 权限粒度 - **页面级权限**: 控制整个页面的访问 - **功能级权限**: 控制页面内特定功能 - **数据级权限**: 控制数据的增删改查 ### 2. 权限设计原则 - **最小权限原则**: 默认拒绝,明确授权 - **角色继承**: 高级角色包含低级角色的权限 - **权限组合**: 支持多角色的权限组合 ### 3. 安全考虑 - **前端权限仅用于UI控制**: 不能作为安全防护的唯一手段 - **后端验证**: 所有敏感操作必须在后端验证权限 - **权限缓存**: 合理缓存权限信息,避免频繁查询 ## 🐛 常见问题 ### 1. 权限指令不生效 检查以下几点: - 指令是否正确注册 - 权限值是否正确传递 - 用户角色信息是否正确加载 ### 2. 动态路由权限问题 确保在路由初始化时正确过滤权限: ```typescript // 在 routeStore.initAuthRoute() 中 const routes = createRoutes(rowRoutes) // 这里会进行权限过滤 ``` ### 3. 权限更新不及时 当用户权限发生变化时: ```typescript // 重新初始化路由 await routeStore.initAuthRoute() // 刷新页面权限 window.location.reload() // 或使用更优雅的方式 ``` ## 📚 相关文档 - [登录鉴权文档](./登录鉴权系统文档) - [路由系统文档](./路由管理系统文档) - [整体架构文档](./整体架构文档)