3、权限模型基础:RBAC、ABAC、PBAC 等经典模型介绍
好,聊完了令牌的生命周期和安全约束,我们该聊聊权限模型了。
你想想看,令牌发出去之后,凭什么决定它能不能访问某个接口、读取某条数据?
背后就是一套权限模型在起作用。说白了,权限模型就是一套规则——谁能对什么资源做什么操作。
几十年来,业界沉淀出了几种经典模型。我个人习惯在做令牌服务之前,先把这部分想清楚,不然业务一复杂,权限就乱成一锅粥。
3.1 RBAC——基于角色的权限控制
RBAC 是大家最熟悉的,也是我最早落地的权限模型。核心思路很简单:把权限赋给角色,再把角色赋给用户。
用户和权限不直接关联。中间隔了一层“角色”。
举个例子:
- 主体(Subject):张三
- 角色(Role):普通用户
- 权限(Permission):查看文章、评章
张三是“普通用户”,而“普通用户”拥有“查看文章”和“评章”的权限。如果明天新增一个“发布文章”功能,我只需要改角色,不用改张三。
核心原则:角色是人肉理解的业务概念,权限是机器执行的原子操作。
我在做早期电商平台时,就用的 RBAC。梳理出“买家”、“卖家”、“客服”、“管理员”4个角色,然后每个角色挂上对应的 API 权限。简洁、直观。但后来问题也暴露了——角色越来越多。
我的经验:RBAC 只适合人员变动不频繁、权限变化小的场景。我见过不少团队把 RBAC 玩成了“角色爆炸”,一个业务场景就创建十几个角色,最后谁也看不清谁有什么权限。
| 优势 | 劣势 |
|---|---|
| 模型简单,易于理解 | 角色膨胀后难以维护 |
| 权限分配效率高 | 无法表达细粒度条件(如时间、地点) |
| 适合中小型系统 | 权限变更通常需要重启或刷新缓存 |
在令牌服务中,RBAC 通常这么落地:
// 令牌解码后,payload 中包含角色信息
{
"sub": "user_123",
"roles": ["buyer", "vip"],
"exp": 1715000000
}
// 网关拦截器判断角色是否在允许列表内
function hasPermission(requiredRole, tokenRoles) {
return tokenRoles.includes(requiredRole);
}
RBAC 很实用,但它没法回答一个问题——如果你是普通用户,但在下午3点到5点之间可以免审核发布商品,该怎么配置?
嗯,这就引出了另一个模型。
3.2 ABAC——基于属性的权限控制
ABAC 不再依赖“角色”这一个维度。它把权限决策拆成了属性的组合。
属性通常分三类:
- 主体属性:用户ID、年龄、部门、角色、信用等级
- 资源属性:资源类型、所有者、分类、地域
- 环境属性:当前时间、IP地址、设备指纹、网络类型
举个例子:
权限规则:“角色是经理,并且当前时间在工作时间(9:00-18:00),并且资源是‘项目部’的文档,才可以删除。”
你会发现,ABAC 的决策表达式比 RBAC 丰富很多。它不是简单的“角色是否在列表里”,而是一段布尔逻辑。
我的感悟:ABAC 是“条件判断”的一次升级。我刚接触 ABAC 时觉得它无所不能,但很快发现——规则写爽了,性能就崩了。
为什么?因为每次请求进来,都要拉一堆属性,然后逐一评估规则。如果属性来源分散(用户服务、资源服务、环境感知模块),那一次请求可能要等几百毫秒。
我曾经踩过一个坑:在做 SaaS 系统的权限优化时,把所有属性都塞进了 Open Policy Agent(OPA)的输入,结果一次评估要查3个远程接口,QPS 直接腰斩。后来我们做了属性预计算 + 缓存,才算稳住。
| 优势 | 劣势 |
|---|---|
| 规则灵活,支持多维度判断 | 属性拉取成本高,容易引发性能瓶颈 |
| 不需要大量角色预设 | 规则编写和维护难,容易产生逻辑漏洞 |
| 天然支持数据级权限 | 调试困难——一条规则正确,多条组合可能出问题 |
在令牌服务中,ABAC 的常见做法是把属性断言留在令牌的 claims 里,或者把策略引擎外挂到网关层。
// ABAC 策略示例(伪代码)
{
"effect": "Allow",
"condition": {
"subject.role": "manager",
"resource.owner": "subject.id",
"environment.time": {"gte": "09:00", "lte": "18:00"}
}
}
3.3 PBAC——基于策略的权限控制
PBAC 这个名字,你可能听得少一点。其实它和 ABAC 有很多重叠,但侧重点不同。
PBAC 强调策略引擎。策略就是一组声明式的规则,通常由专门的语言(如 XACML、Rego)编写。
它的核心思路是:把权限决策从业务代码中完全抽离出来。
一个典型的 PBAC 流程有4个角色:
- 策略决策点(PDP):中心化的评估引擎,接收“主体-资源-动作”三元组,返回 Permit/Deny
- 策略执行点(PEP):网关或服务端拦截请求,调用 PDP
- 策略信息点(PIP):提供主体、资源、环境等属性数据
- 策略管理点(PAP):编写、测试、部署策略的地方
举个例子:
// 使用 Rego(OPA 的策略语言)编写 PBAC 规则
package example.authz
default allow = false
allow {
input.subject.role == "admin"
}
allow {
input.subject.role == "user"
input.resource.type == "article"
input.action == "read"
}
allow {
input.subject.role == "vip"
input.resource.type == "article"
input.action == "write"
input.resource.owner == input.subject.id
}
你看,每条规则都是一个独立的 `allow` 子句。只要有一条匹配,就放行。这种“白名单叠加”的写法,比手写 if-else 清爽不止一点点。
我在一个 IoT 平台项目中落地过 PBAC。设备类型 500+、用户角色 20+、还有几十种地理位置规则。如果用 RBAC,角色会多到没人敢改;用 ABAC,每次请求评估要查大量属性。
PBAC 帮我们做了策略缓存 + 批量评估,把平均决策耗时控制在 5ms 以内。
| 优势 | 劣势 |
|---|---|
| 策略与代码完全解耦,支持热更新 | 引入独立 PDP,增加架构复杂度 |
| 策略可测试、可审计、可版本管理 | 调试门槛高,需要熟悉策略语言 |
| 适合超大规模、跨部门权限场景 | 简单场景没必要,属于杀鸡用牛刀 |
一句话总结三者的关系: RBAC 最通用,适合 80% 的系统;ABAC 最灵活,解决 RBAC 够不到的条件判断;PBAC 最强大,把权限决策变成一种可编程的服务。
那么,在令牌服务中我怎么选?
- 场景简单、用户量不大 → RBAC 就够了。别折腾。
- 需要根据时间、地点、行为动态控制 → ABAC 是你的菜。
- 大型企业、多租户、权限规则经常变 → 上 PBAC,把策略交给业务团队自己维护。
下面这张图,直观展示了三种模型的核心区别。
一个实用的建议:我不推荐一上来就上 PBAC。先跑通 RBAC,如果发现角色和条件判断越来越多,再逐步往 ABAC 或 PBAC 迁移。很多大型系统到最后其实都是混合模型——基础权限用 RBAC,特殊场景用 ABAC 或 PBAC 兜底。