2、权限矩阵模型:RBAC模型介绍、权限矩阵的存储结构(用户-角色-权限)、JWT中嵌入权限信息的常见方式
2.1 RBAC 模型:从用户到权限的标准化映射
基于角色的访问控制(RBAC)是业界最成熟的权限管理模型之一。其核心思想是将“权限”与“角色”绑定,再将“角色”授予“用户”,从而在用户与权限之间建立一层间接抽象。这种设计大幅降低了权限管理的复杂度,尤其适合企业级后端系统。
RBAC 模型包含三个基本实体:
- 用户(User):系统的操作主体,可以是一个人、一个服务账号或一个设备。
- 角色(Role):权限的集合,代表一类职责或岗位,例如“管理员”、“编辑”、“审计员”。
- 权限(Permission):对某个资源执行特定操作的许可,通常表示为
resource:action格式,例如order:create、report:export。
RBAC 核心优势:当组织内新增用户时,只需为其分配已有角色,无需逐条配置权限;当业务权限变更时,只需修改角色与权限的关联,所有拥有该角色的用户自动生效。
2.2 权限矩阵的存储结构:用户-角色-权限三层关联
在关系型数据库中,RBAC 通常通过三张核心表及两张关联表实现。以下为标准的五表结构设计:
| 表名 | 字段示例 | 说明 |
|---|---|---|
users |
id, username, password_hash | 用户主体表 |
roles |
id, role_name, description | 角色定义表 |
permissions |
id, resource, action | 权限原子表 |
user_roles |
user_id, role_id | 用户与角色的多对多关联 |
role_permissions |
role_id, permission_id | 角色与权限的多对多关联 |
查询某个用户的所有权限时,执行以下 SQL 关联:
SELECT p.resource, p.action
FROM users u
JOIN user_roles ur ON u.id = ur.user_id
JOIN roles r ON ur.role_id = r.id
JOIN role_permissions rp ON r.id = rp.role_id
JOIN permissions p ON rp.permission_id = p.id
WHERE u.id = ?;
这种存储结构在数据层面保证了权限的完整性和一致性,但在高并发场景下,每次请求都执行多表 JOIN 查询会带来显著的性能开销。这正是后续章节引入缓存策略的直接动因。
设计建议:权限的
resource 和 action 字段建议使用枚举或短字符串,并建立联合索引,以加速权限查询。
2.3 JWT 中嵌入权限信息的常见方式
将权限信息嵌入 JWT 令牌,可以使后端服务在无状态鉴权时直接获取用户的权限矩阵,避免每次请求都回查数据库。根据业务规模和性能要求,主要有以下三种嵌入策略:
方式一:直接嵌入角色列表(轻量级)
在 JWT 的 payload 中仅存放用户所属的角色名称列表。后端收到请求后,从令牌中提取角色,再通过本地缓存或内存中的角色-权限映射表完成鉴权。
{
"sub": "user_1001",
"roles": ["admin", "editor"],
"iat": 1710000000,
"exp": 1710003600
}
适用场景:角色数量少(通常 < 20 个),且角色与权限的映射关系相对稳定。
方式二:嵌入权限标识列表(精细粒度)
直接将用户拥有的所有权限标识(如 order:create、report:export)放入 JWT。后端无需二次查询即可完成精确鉴权。
{
"sub": "user_1001",
"permissions": [
"order:create",
"order:view",
"report:export",
"user:manage"
],
"iat": 1710000000,
"exp": 1710003600
}
适用场景:权限粒度要求精细,且单个用户的权限数量可控(通常 < 200 条)。
性能警告:当用户权限数量超过 500 条时,JWT 的 payload 体积会显著增大,导致每次请求的 HTTP 头部传输开销上升,同时增加令牌签发和验签的耗时。此时应考虑方式三或引入压缩策略。
方式三:嵌入权限位图(极致性能)
将权限系统预定义为一个有序的权限列表,每个权限对应一个二进制位。用户的权限集合通过一个位图(Bitmap)表示,JWT 中仅存储该位图的整数值或 Base64 编码字符串。
// 权限定义索引
// 0: order:create
// 1: order:view
// 2: order:delete
// 3: report:export
// 4: user:manage
// 用户拥有 order:create, order:view, report:export
// 位图: 1 1 0 1 0 → 二进制 11010 → 十进制 26
{
"sub": "user_1001",
"perm_bitmap": 26,
"iat": 1710000000,
"exp": 1710003600
}
适用场景:权限总数固定且较少(通常 < 64 个),对令牌体积和解析速度有极致要求的场景。
2.4 三种嵌入方式对比
| 对比维度 | 角色列表 | 权限标识列表 | 权限位图 |
|---|---|---|---|
| 令牌体积 | 小 | 中~大 | 极小 |
| 鉴权速度 | 中(需查角色-权限映射) | 快(直接匹配) | 极快(位运算) |
| 扩展性 | 高(角色增删不影响令牌) | 低(权限变更需重新签发令牌) | 中(权限列表重排需同步更新) |
| 实现复杂度 | 低 | 中 | 高 |
| 推荐场景 | 角色少、权限层级简单 | 权限粒度细、数量适中 | 高并发、权限总数固定 |
2.5 权限矩阵与 JWT 嵌入的整体架构
下图展示了从数据库存储到 JWT 签发,再到请求鉴权的完整数据流: