coder-common-thin-frontend/doc/权限管理系统文档.md
2025-07-04 15:08:19 +08:00

390 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<HTMLElement, Entity.RoleType | Entity.RoleType[]> = {
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
<template>
<!-- 只有 admin 角色可见 -->
<button v-permission="'admin'">管理员功能</button>
<!-- admin editor 角色可见 -->
<div v-permission="['admin', 'editor']">
编辑内容
</div>
<!-- super 角色可见 -->
<section v-permission="'super'">
超级管理员专用区域
</section>
</template>
```
## 🛣️ 路由权限控制
### 路由元信息配置
```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
<script setup>
import { usePermission } from '@/hooks'
const { hasPermission } = usePermission()
// 编程式权限检查
const canEdit = computed(() => hasPermission(['admin', 'editor']))
const canDelete = computed(() => hasPermission('admin'))
</script>
<template>
<div>
<!-- 指令式权限控制 -->
<button v-permission="'admin'">删除</button>
<!-- 编程式权限控制 -->
<button v-if="canEdit">编辑</button>
<!-- 条件渲染 -->
<div v-if="hasPermission('super')">
超级管理员专用功能
</div>
</div>
</template>
```
### 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() // 或使用更优雅的方式
```
## 📚 相关文档
- [登录鉴权文档](./登录鉴权系统文档)
- [路由系统文档](./路由管理系统文档)
- [整体架构文档](./整体架构文档)