4-1 权限控制导学:权限控制数据设计(预习作业)
前端权限与后端权限的区别
在进入权限控制的学习之前,先理清前端权限和后端权限的差异,这有助于后续理解整个权限体系。
前端权限
前端权限主要分两层:
| 层级 | 名称 | 实现方式 | 说明 |
|---|---|---|---|
| 第一层 | 路由/菜单权限 | 路由守卫(前置/后置) | 通过 Vue/React 的 Router Provider,判断用户角色或菜单配置,控制页面访问 |
| 第二层 | 操作权限 | 条件渲染 | 在具体页面上,根据用户是否拥有新增、删除、编辑等按钮权限来控制 UI 展示 |
关键原则:前端权限必须依托后端。如果把权限逻辑只写在前端,用户可以通过浏览器控制台绕过限制,权限就失去了意义。
后端权限
后端权限同样分两层:
| 层级 | 名称 | 说明 |
|---|---|---|
| 第一层 | 接口权限 | 控制哪些接口用户可以访问 |
| 第二层 | 数据权限 | 即使能访问接口,也并非所有数据都能读取 |
不可能将所有用户与所有接口的权限关系写入同一张表格——当用户数达到 1000、接口数达到 200 时,数据量将指数级增长。因此业界发展出多种经典权限模型来封装和管理这些关系。
五种主流权限模型
| 模型 | 全称 | 核心思路 | 优点 | 缺点 | 典型场景 |
|---|---|---|---|---|---|
| ACL | Access Control List | 基于客体控制,每个客体维护一张可访问主体列表 | 简单直观 | 主体数量多时配置和维护成本大 | 早期文件系统 |
| DAC | Discretionary Access Control | ACL 的扩展,主体可自主将权限授予其他主体 | 灵活授权 | 权限控制分散,主体权限过大可能无意泄露 | Linux/Windows NT 文件系统 |
| MAC | Mandatory Access Control | 双向验证——主体和客体各有权限标识,操作取决于双方关系 | 安全性高 | 控制过严,实现工作量大,缺乏灵活性 | 军事、安全等级领域 |
| ABAC | Attribute-Based Access Control | 动态计算主体属性、客体属性、环境属性、操作属性是否满足条件 | 灵活,可按需实现不同颗粒度 | 规则复杂,实现困难,应用较少 | 复杂业务规则场景 |
| RBAC | Role-Based Access Control | 用户只和角色关联,角色代表权限集合,用户通过成为角色成员获得权限 | 便于角色划分,授权管理灵活 | 角色爆炸风险(角色数量过多) | 企业级应用主流方案 |
ABAC 四类属性详解
ABAC 通过动态计算属性是否满足某种条件来授权,属性分为四类:
- 主体属性:用户年龄、性别、部门等
- 客体属性:资源的类型、创建者等
- 环境属性:时间、空间限制等
- 操作属性:读写、只读等
RBAC 深度解析
本课程重点学习 RBAC 模型,它是企业级应用中使用最广泛的权限控制方案。
RBAC 三要素
┌──────────┐ 多对多 ┌──────────┐ 多对多 ┌──────────────┐
│ User │ ◄────────────► │ Role │ ◄────────────► │ Permission │
│ 用户表 │ │ 角色表 │ │ 权限表 │
└──────────┘ └──────────┘ └──────────────┘
text
- 用户(User):系统中所有账户
- 角色(Role):一系列权限的集合(如管理员、开发者、审计员)
- 权限(Permission):菜单、按钮、数据的增删改查等详细权限
RBAC 的四个层级
| 层级 | 特性 | 说明 | 适用场景 |
|---|---|---|---|
| RBAC0 | 基础模型 | 用户和角色、角色和权限都是多对多关系 | 大部分企业应用 |
| RBAC1 | 角色继承 | 在 RBAC0 基础上增加角色分级,子角色继承父角色权限 | 需要层级管理的组织 |
| RBAC2 | 角色约束 | 在 RBAC0 基础上增加约束条件(互斥、数量限制等) | 需要职责分离的系统 |
| RBAC3 | 综合 | RBAC1 + RBAC2 的所有特点 | 复杂企业级系统 |
RBAC1 角色继承示例:
经理(Manager)
├── 主管(Supervisor) → 继承经理权限,可针对性删减
└── 专员(Staff) → 继承经理权限,可针对性删减
text
RBAC2 常见约束:
- 角色互斥:财务系统中出纳和稽核不能由同一人兼任
- 角色数量限制:CEO 角色不应有 10 个人拥有
RBAC 实际应用中的实践要点
用户管理:直接使用企业部门架构或业务线架构来构建,注意实际业务中的组织架构可能与部门架构不同,需要考虑数据共享机制。
角色管理:深入理解业务逻辑后再设计,一般使用各部门真实角色为基础再扩展。关键实践:
| 实践 | 说明 |
|---|---|
| 入职自动赋权 | 入职自动获得基础角色,减少管理员手动操作 |
| 临时角色 | 设置失效时间,避免临时账号遗留安全隐患 |
| 虚拟角色 | 处理超出角色等级的特殊权限需求 |
| 白名单 | 管理特殊高级权限用户 |
| 黑名单 | 限制犯错员工的权限 |
权限管理:从三个层面做限制:
| 层面 | 说明 | 示例 |
|---|---|---|
| 页面/菜单权限 | 隐藏无权限的页面入口或菜单选项 | 普通用户看不到"系统管理"菜单 |
| 操作权限 | 控制同一组数据上不同用户的增删改查能力 | 普通用户只能查看,管理员可编辑 |
| 数据权限 | 在数据接口层面做限制,防止非法操作 | 行权限(看多少条数据)+ 列权限(看一条数据的多少字段) |
NestJS 中的两种 RBAC 实现方式
在 NestJS 中实现 RBAC 有两种方案:
| 方案 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| 动态方案 | 权限信息存储在数据库中(User、Role、Permission 表),Guard 中从数据库读取配置进行判断 | 灵活度高,运行时可调整 | 复杂度高,需要数据库查询 |
| 静态方案 | 在 Controller 或路由上通过装饰器添加 Meta 信息,判断用户是否拥有对应角色 | 简单直接,性能好 | 角色信息写死在程序中,修改需重新部署 |
静态方案:基于装饰器的 RBAC 实现
使用 SetMetadata 和自定义装饰器实现基础的 RBAC:
// roles.decorator.ts
import { SetMetadata } from '@nestjs/common';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
typescript
// roles.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ROLES_KEY } from './roles.decorator';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true; // 没有设置角色要求,放行
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some((role) => user.roles?.includes(role));
}
}
typescript
// user.controller.ts
import { Controller, Delete, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Roles } from './roles.decorator';
import { RolesGuard } from './roles.guard';
@Controller('users')
@UseGuards(AuthGuard, RolesGuard)
export class UserController {
@Delete(':id')
@Roles('admin')
remove(@Param('id') id: string) {
return this.userService.remove(id);
}
}
typescript
动态方案:基于 CASL 的策略权限控制
NestJS 官方文档还介绍了与 CASL 库集成的基于策略的权限控制(Claims-based Authorization),可以实现更细粒度的资源实例级权限控制。这种方式允许定义策略,策略列表针对某个接口的增删改查操作进行精确控制。
预习作业
自行尝试 NestJS 官方权限部分的示例代码,体验 RBAC 和 ACL 两种权限控制方式的实现。
参考资源:
- NestJS 官方文档 - Authorization
- 基础 RBAC 实现:使用
@Roles()装饰器 +RolesGuard - 基于 Claim(策略)的实现:使用 CASL 库进行细粒度权限控制
↑