2026-03-27 22:20:25 +08:00
|
|
|
|
# RBAC 权限控制详解
|
|
|
|
|
|
|
|
|
|
|
|
## 📚 什么是 RBAC?
|
|
|
|
|
|
|
|
|
|
|
|
**RBAC(Role-Based Access Control)** 即**基于角色的访问控制**,是一种权限管理模型。它的核心思想是:
|
|
|
|
|
|
|
|
|
|
|
|
> **用户 → 角色 → 权限**
|
|
|
|
|
|
|
|
|
|
|
|
通过给用户分配角色,角色拥有权限,从而间接地给用户授予权限。
|
|
|
|
|
|
|
|
|
|
|
|
## 🎯 RBAC 的核心概念
|
|
|
|
|
|
|
|
|
|
|
|
### 1. **用户(User)**
|
|
|
|
|
|
|
|
|
|
|
|
系统中的实际使用者,如:张三、李四
|
|
|
|
|
|
|
|
|
|
|
|
### 2. **角色(Role)**
|
|
|
|
|
|
|
|
|
|
|
|
一组权限的集合,如:管理员、编辑、访客
|
|
|
|
|
|
|
|
|
|
|
|
### 3. **权限(Permission)**
|
|
|
|
|
|
|
|
|
|
|
|
对资源的操作能力,如:创建用户、删除文章、查看报表
|
|
|
|
|
|
|
|
|
|
|
|
### 4. **资源(Resource)**
|
|
|
|
|
|
|
|
|
|
|
|
系统中的实体对象,如:用户、文章、订单
|
|
|
|
|
|
|
|
|
|
|
|
### 5. **操作(Action)**
|
|
|
|
|
|
|
|
|
|
|
|
对资源的操作类型,如:create(创建)、read(查看)、update(更新)、delete(删除)
|
|
|
|
|
|
|
|
|
|
|
|
## 🏗️ 项目中的 RBAC 架构
|
|
|
|
|
|
|
|
|
|
|
|
### 数据模型关系
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
User (用户)
|
|
|
|
|
|
↓ (多对多)
|
|
|
|
|
|
UserRole (用户角色关联)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Role (角色)
|
|
|
|
|
|
↓ (多对多)
|
|
|
|
|
|
RolePermission (角色权限关联)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Permission (权限)
|
|
|
|
|
|
├─ resource: 资源名称 (如: user, role, menu)
|
|
|
|
|
|
└─ action: 操作类型 (如: create, read, update, delete)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 数据库表结构
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. **users** - 用户表
|
|
|
|
|
|
|
|
|
|
|
|
存储系统用户的基本信息
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. **roles** - 角色表
|
|
|
|
|
|
|
|
|
|
|
|
存储角色信息,如:
|
|
|
|
|
|
|
|
|
|
|
|
- `admin` - 管理员
|
|
|
|
|
|
- `editor` - 编辑
|
|
|
|
|
|
- `viewer` - 查看者
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. **permissions** - 权限表
|
|
|
|
|
|
|
|
|
|
|
|
存储权限信息,权限由 `resource` + `action` 组成,如:
|
|
|
|
|
|
|
|
|
|
|
|
- `user:create` - 创建用户
|
|
|
|
|
|
- `user:read` - 查看用户
|
|
|
|
|
|
- `user:update` - 更新用户
|
|
|
|
|
|
- `user:delete` - 删除用户
|
|
|
|
|
|
- `role:create` - 创建角色
|
|
|
|
|
|
- `menu:read` - 查看菜单
|
|
|
|
|
|
|
|
|
|
|
|
#### 4. **user_roles** - 用户角色关联表
|
|
|
|
|
|
|
|
|
|
|
|
用户和角色的多对多关系
|
|
|
|
|
|
|
|
|
|
|
|
#### 5. **role_permissions** - 角色权限关联表
|
|
|
|
|
|
|
|
|
|
|
|
角色和权限的多对多关系
|
|
|
|
|
|
|
|
|
|
|
|
## 🔄 RBAC 工作流程
|
|
|
|
|
|
|
|
|
|
|
|
### 1. **权限分配流程**
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
1. 创建权限
|
|
|
|
|
|
└─> 定义资源(resource)和操作(action)
|
|
|
|
|
|
└─> 例如:user:create, user:read
|
|
|
|
|
|
|
|
|
|
|
|
2. 创建角色
|
|
|
|
|
|
└─> 给角色分配权限
|
|
|
|
|
|
└─> 例如:管理员角色 = [user:create, user:read, user:update, user:delete]
|
|
|
|
|
|
|
|
|
|
|
|
3. 给用户分配角色
|
|
|
|
|
|
└─> 用户继承角色的所有权限
|
|
|
|
|
|
└─> 例如:张三 = 管理员角色
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. **权限验证流程**
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
用户请求 API
|
|
|
|
|
|
↓
|
|
|
|
|
|
JWT 认证(验证用户身份)
|
|
|
|
|
|
↓
|
|
|
|
|
|
提取用户信息(包含 roles 和 permissions)
|
|
|
|
|
|
↓
|
|
|
|
|
|
RolesGuard 检查(检查用户是否有指定角色)
|
|
|
|
|
|
↓
|
|
|
|
|
|
PermissionGuard 检查(检查用户是否有指定权限)
|
|
|
|
|
|
↓
|
|
|
|
|
|
允许/拒绝访问
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 💻 代码实现示例
|
|
|
|
|
|
|
|
|
|
|
|
### 1. **定义权限**
|
|
|
|
|
|
|
|
|
|
|
|
权限由 `resource` + `action` 组成:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 权限示例
|
|
|
|
|
|
{
|
|
|
|
|
|
code: 'user:create', // 权限编码
|
|
|
|
|
|
resource: 'user', // 资源:用户
|
|
|
|
|
|
action: 'create', // 操作:创建
|
|
|
|
|
|
name: '创建用户',
|
|
|
|
|
|
description: '允许创建新用户'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
code: 'user:read',
|
|
|
|
|
|
resource: 'user',
|
|
|
|
|
|
action: 'read',
|
|
|
|
|
|
name: '查看用户',
|
|
|
|
|
|
description: '允许查看用户列表和详情'
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. **创建角色并分配权限**
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 创建管理员角色
|
|
|
|
|
|
const adminRole = await prisma.role.create({
|
|
|
|
|
|
data: {
|
|
|
|
|
|
name: '管理员',
|
|
|
|
|
|
code: 'admin',
|
|
|
|
|
|
permissions: {
|
|
|
|
|
|
create: [
|
|
|
|
|
|
{ permission: { connect: { code: 'user:create' } } },
|
|
|
|
|
|
{ permission: { connect: { code: 'user:read' } } },
|
|
|
|
|
|
{ permission: { connect: { code: 'user:update' } } },
|
|
|
|
|
|
{ permission: { connect: { code: 'user:delete' } } },
|
|
|
|
|
|
{ permission: { connect: { code: 'role:create' } } },
|
|
|
|
|
|
// ... 更多权限
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. **给用户分配角色**
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 给用户分配管理员角色
|
|
|
|
|
|
await prisma.userRole.create({
|
|
|
|
|
|
data: {
|
|
|
|
|
|
user: { connect: { id: userId } },
|
|
|
|
|
|
role: { connect: { code: 'admin' } },
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4. **在控制器中使用权限控制**
|
|
|
|
|
|
|
|
|
|
|
|
#### 方式一:使用角色装饰器
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
import { Controller, Get, UseGuards } from '@nestjs/common';
|
|
|
|
|
|
import { Roles } from '../auth/decorators/roles.decorator';
|
|
|
|
|
|
import { RolesGuard } from '../auth/guards/roles.guard';
|
|
|
|
|
|
|
|
|
|
|
|
@Controller('users')
|
|
|
|
|
|
@UseGuards(RolesGuard)
|
|
|
|
|
|
export class UsersController {
|
|
|
|
|
|
@Get()
|
|
|
|
|
|
@Roles('admin', 'editor') // 需要 admin 或 editor 角色
|
|
|
|
|
|
findAll() {
|
|
|
|
|
|
// 只有拥有 admin 或 editor 角色的用户才能访问
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Delete(':id')
|
|
|
|
|
|
@Roles('admin') // 只有 admin 角色可以删除
|
|
|
|
|
|
remove() {
|
|
|
|
|
|
// 只有管理员可以删除用户
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 方式二:使用权限装饰器(可扩展)
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 可以创建 PermissionGuard 和 @Permissions() 装饰器
|
|
|
|
|
|
@Get()
|
|
|
|
|
|
@Permissions('user:read') // 需要 user:read 权限
|
|
|
|
|
|
findAll() {
|
|
|
|
|
|
// 只有拥有 user:read 权限的用户才能访问
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 5. **获取用户权限**
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 在 AuthService 中
|
|
|
|
|
|
private async getUserPermissions(userId: number): Promise<string[]> {
|
|
|
|
|
|
const user = await this.usersService.findOne(userId);
|
|
|
|
|
|
if (!user) return [];
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
// 返回: ['user:create', 'user:read', 'user:update', 'role:create', ...]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 📊 RBAC 的优势
|
|
|
|
|
|
|
|
|
|
|
|
### 1. **灵活性**
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ 一个用户可以有多个角色
|
|
|
|
|
|
- ✅ 一个角色可以有多个权限
|
|
|
|
|
|
- ✅ 权限可以动态分配和回收
|
|
|
|
|
|
|
|
|
|
|
|
### 2. **可维护性**
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ 权限变更只需修改角色,不需要逐个修改用户
|
|
|
|
|
|
- ✅ 角色可以复用,减少重复配置
|
|
|
|
|
|
|
|
|
|
|
|
### 3. **可扩展性**
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ 新增资源只需添加新的权限
|
|
|
|
|
|
- ✅ 新增角色只需组合现有权限
|
|
|
|
|
|
|
|
|
|
|
|
### 4. **安全性**
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ 最小权限原则:用户只获得必要的权限
|
|
|
|
|
|
- ✅ 权限集中管理,便于审计
|
|
|
|
|
|
|
|
|
|
|
|
## 🎨 实际应用场景
|
|
|
|
|
|
|
|
|
|
|
|
### 场景 1:内容管理系统
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
角色定义:
|
|
|
|
|
|
- 超级管理员:所有权限
|
|
|
|
|
|
- 内容管理员:文章 CRUD、评论管理
|
|
|
|
|
|
- 编辑:文章创建、编辑
|
|
|
|
|
|
- 作者:文章创建
|
|
|
|
|
|
- 访客:文章查看
|
|
|
|
|
|
|
|
|
|
|
|
权限示例:
|
|
|
|
|
|
- article:create
|
|
|
|
|
|
- article:read
|
|
|
|
|
|
- article:update
|
|
|
|
|
|
- article:delete
|
|
|
|
|
|
- comment:moderate
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 场景 2:电商系统
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
角色定义:
|
|
|
|
|
|
- 平台管理员:所有权限
|
|
|
|
|
|
- 店铺管理员:店铺管理、订单管理
|
|
|
|
|
|
- 客服:订单查看、退款处理
|
|
|
|
|
|
- 财务:订单查看、财务报表
|
|
|
|
|
|
|
|
|
|
|
|
权限示例:
|
|
|
|
|
|
- order:create
|
|
|
|
|
|
- order:read
|
|
|
|
|
|
- order:update
|
|
|
|
|
|
- order:refund
|
|
|
|
|
|
- report:financial
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 🔐 项目中的权限控制实现
|
|
|
|
|
|
|
|
|
|
|
|
### 1. **JWT 认证**
|
|
|
|
|
|
|
|
|
|
|
|
用户登录后获得 JWT Token,Token 中包含用户 ID
|
|
|
|
|
|
|
|
|
|
|
|
### 2. **JwtAuthGuard**
|
|
|
|
|
|
|
|
|
|
|
|
验证 JWT Token,提取用户信息
|
|
|
|
|
|
|
|
|
|
|
|
### 3. **RolesGuard**
|
|
|
|
|
|
|
|
|
|
|
|
检查用户是否拥有指定的角色
|
|
|
|
|
|
|
|
|
|
|
|
### 4. **权限获取**
|
|
|
|
|
|
|
|
|
|
|
|
登录时,系统会:
|
|
|
|
|
|
|
|
|
|
|
|
1. 查询用户的所有角色
|
|
|
|
|
|
2. 查询角色关联的所有权限
|
|
|
|
|
|
3. 合并所有权限并返回给前端
|
|
|
|
|
|
|
|
|
|
|
|
### 5. **前端权限控制**
|
|
|
|
|
|
|
|
|
|
|
|
前端可以根据返回的 `roles` 和 `permissions` 数组:
|
|
|
|
|
|
|
|
|
|
|
|
- 控制菜单显示
|
|
|
|
|
|
- 控制按钮显示
|
|
|
|
|
|
- 控制路由访问
|
|
|
|
|
|
|
|
|
|
|
|
## 📝 最佳实践
|
|
|
|
|
|
|
|
|
|
|
|
### 1. **权限命名规范**
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
格式:resource:action
|
|
|
|
|
|
示例:
|
|
|
|
|
|
- user:create
|
|
|
|
|
|
- user:read
|
|
|
|
|
|
- user:update
|
|
|
|
|
|
- user:delete
|
|
|
|
|
|
- role:assign
|
|
|
|
|
|
- menu:manage
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. **角色命名规范**
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
使用有意义的英文代码:
|
|
|
|
|
|
- admin: 管理员
|
|
|
|
|
|
- editor: 编辑
|
|
|
|
|
|
- viewer: 查看者
|
|
|
|
|
|
- guest: 访客
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. **权限粒度**
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ 不要过粗:避免一个权限包含太多操作
|
|
|
|
|
|
- ✅ 不要过细:避免权限过多难以管理
|
|
|
|
|
|
- ✅ 按业务模块划分:user、role、menu、dict 等
|
|
|
|
|
|
|
|
|
|
|
|
### 4. **默认角色**
|
|
|
|
|
|
|
|
|
|
|
|
建议创建以下默认角色:
|
|
|
|
|
|
|
|
|
|
|
|
- **超级管理员**:拥有所有权限
|
|
|
|
|
|
- **普通用户**:基础查看权限
|
|
|
|
|
|
- **访客**:只读权限
|
|
|
|
|
|
|
|
|
|
|
|
## 🚀 扩展功能
|
|
|
|
|
|
|
|
|
|
|
|
### 1. **权限继承**
|
|
|
|
|
|
|
|
|
|
|
|
可以实现角色继承,子角色继承父角色的权限
|
|
|
|
|
|
|
|
|
|
|
|
### 2. **动态权限**
|
|
|
|
|
|
|
|
|
|
|
|
可以根据数据范围动态控制权限,如:
|
|
|
|
|
|
|
|
|
|
|
|
- 用户只能管理自己创建的订单
|
|
|
|
|
|
- 部门管理员只能管理本部门的用户
|
|
|
|
|
|
|
|
|
|
|
|
### 3. **权限缓存**
|
|
|
|
|
|
|
|
|
|
|
|
将用户权限缓存到 Redis,提高性能
|
|
|
|
|
|
|
|
|
|
|
|
### 4. **权限审计**
|
|
|
|
|
|
|
|
|
|
|
|
记录权限变更日志,便于追溯
|
|
|
|
|
|
|
|
|
|
|
|
## 📖 总结
|
|
|
|
|
|
|
|
|
|
|
|
RBAC 权限控制通过 **用户 → 角色 → 权限** 的三层关系,实现了灵活、可维护的权限管理系统。在你的项目中:
|
|
|
|
|
|
|
|
|
|
|
|
1. ✅ **用户** 通过 `user_roles` 表关联 **角色**
|
|
|
|
|
|
2. ✅ **角色** 通过 `role_permissions` 表关联 **权限**
|
|
|
|
|
|
3. ✅ **权限** 由 `resource` + `action` 组成
|
|
|
|
|
|
4. ✅ 使用 `@Roles()` 装饰器控制接口访问
|
|
|
|
|
|
5. ✅ 登录时返回用户的角色和权限列表
|
|
|
|
|
|
|
|
|
|
|
|
这样的设计既保证了安全性,又提供了良好的扩展性和可维护性!
|