# 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 { const user = await this.usersService.findOne(userId); if (!user) return []; const permissions = new Set(); // 遍历用户的所有角色 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. ✅ 登录时返回用户的角色和权限列表 这样的设计既保证了安全性,又提供了良好的扩展性和可维护性!