第二章 权限模型基础:概念、ACL、RBAC、ABAC
权限模型这东西,说白了就是回答两个问题:谁能对什么资源做什么操作。我刚入行时总觉得这玩意儿简单,不就是建个表存权限吗?直到被线上事故教育了几次,才明白选错模型多要命。这一章咱们把几个经典模型掰开揉碎,看看它们各自长什么样、用在哪儿、又死在哪儿。
2.1 权限模型的三要素
不管什么模型,核心骨架都一样。你想想看,任何一个权限判断都能拆成三部分:
- 主体(Subject)——谁要做事。用户、角色、服务账户都算。
- 资源(Resource)——对什么东西做事。文件、API、数据库记录都是资源。
- 操作(Operation)——做什么事。读、写、删除、执行,各系统自己定义。
整个权限模型的演进史,就是不断给这三者之间加“缓冲层”和“条件”的过程。嗯,记住这个视角,后面看模型会更清楚。
2.2 ACL – 访问控制列表
ACL 是最直白的模型。它直接列出一张表:某主体 → 某资源 → 允许/拒绝某操作。Unix 文件权限就是个经典例子:
# 文件 /etc/passwd 的 ACL(简化)
用户 root: rw-
用户 alice: r--
所有人: r--
优点很明显:精确、灵活,每个资源能单独控制。但一旦资源多、用户多,这张表膨胀得比你想象快得多。我在一个电商后台见过 ACL 表超过 1 亿行,查询一次要扫全表……那场面,简直灾难。
ACL 的数据模型大概长这样:
| 主体 | 资源 | 操作 | 效果 |
|---|---|---|---|
| Alice | 文档-001 | 读取 | 允许 |
| Bob | 文档-001 | 写入 | 允许 |
| Bob | 文档-002 | 读取 | 允许 |
注意:每个主体-资源对都得一条记录。一旦资源上万,主体上千,ACL 表的行数就是千万级。
2.3 RBAC – 基于角色的访问控制
RBAC 加了一层“角色”。你不直接给用户分配权限,而是把权限捆成角色,再把角色给用户。你想想看,这不就是现实公司的做法吗?你是开发 -> 拥有 git push 权限;你是测试 -> 拥有 bug 管理权限。一句话:用户-角色-权限三层结构。
RBAC 有四个核心要素:
- 用户 – 系统账号
- 角色 – 职责集合,比如“管理员”、“编辑”
- 权限 – 资源+操作
- 会话 – 用户激活的角色组合(NIST RBAC 标准里强调的)
NIST RBAC 标准把模型分了三层:
| 层次 | 说明 | 典型用例 |
|---|---|---|
| 扁平 RBAC | 用户-角色-权限,角色不继承 | 小团队内部系统 |
| 层级 RBAC | 角色可继承(如超级管理员继承普通管理员) | 企业组织架构 |
| 约束 RBAC | 加职责分离(同一人不能同时拥有两个互斥角色) | 金融、审计 |
我自己实践中最顺手的 RBAC 表结构是这样的:
-- 核心表
users(id, name)
roles(id, name, parent_role_id)
permissions(id, resource, operation)
role_permissions(role_id, permission_id)
user_roles(user_id, role_id)
注意:角色继承要小心循环。我见过一个团队手动维护 parent_role_id,结果自己写了个死循环。建议用闭包表或者 Nested Set 来存角色树。
2.4 ABAC – 基于属性的访问控制
ABAC 是更灵活的模型。它不依赖固定的角色列表,而是用属性来做判断。属性来源三处:
- 主体属性:年龄、部门、职级、安全等级
- 资源属性:机密级别、创建时间、所属项目
- 环境属性:时间、IP 地址、设备类型
策略引擎根据属性表达式决定是否放行。举个例子:
策略:允许读取 当 用户.部门 == 资源.所属部门 AND 用户.职级 >= 3 AND 当前时间 IN 09:00-18:00
这不就是“如果……那么……”的逻辑吗?说白了,ABAC 把权限判断变成了规则引擎。
三个模型的关键差异,我给你列个表:
| 维度 | ACL | RBAC | ABAC |
|---|---|---|---|
| 管理粒度 | 单个主体-资源对 | 角色级别 | 属性级别(动态) |
| 规模弹性 | 差(O(n*m)) | 好(角色数量可控) | 好(策略复用) |
| 易理解性 | 直观 | 符合组织直觉 | 需要策略工程师 |
| 动态条件 | 不支持 | 不支持(纯静态) | 支持时间、IP 等 |
| 审计难度 | 低 | 中 | 高(需记录策略上下文) |
2.5 模型选择:什么时候用哪个?
没有银弹。我的做法是根据系统复杂度画一条分界线:
- 单机工具、小型系统(<100 用户,<50 资源)→ 用 ACL,简单直接。
- 企业应用、SaaS 平台(100-10 万用户)→ 用 RBAC + 一点 ABAC 扩展。
- 大型分布式、IoT、实时风控 → 用 ABAC 或 PBAC(策略基访问控制)。
你想想看,一个 ERP 系统如果有 500 个权限点、50 种角色,RBAC 管理起来很舒服。但如果要求“周末凌晨只能由主管级以上的运维操作”,那就必须上 ABAC 了。现实系统往往是混合的——核心流程用 RBAC 兜底,边界条件用 ABAC 打补丁。
这张图把三要素和三个模型的关系串起来了。你可以看到:ACL 直接从主体到资源,没有中间层;RBAC 在中间加了角色;ABAC 则把判断逻辑交给了属性规则。从左上到右下,灵活性递增,但可管理性递减。
2.6 从ACL到ABAC的演进路径
我见过不少团队是这么进化的:
- 阶段一:直接硬编码。 if (user == 'admin') { allow }。这种代码我当年也写过,后来维护起来想骂人。
- 阶段二:ACL表。 把所有允许关系写成数据库行。能用,但到几千用户后开始卡。
- 阶段三:RBAC。 抽象出角色,权限集中管理。这是大多数系统的成熟形态。
- 阶段四:ABAC混合。 在RBAC基础上增加属性策略,处理跨部门、多租户等复杂场景。
有个细节:从ACL切换到RBAC时,最痛的不是改代码,而是清洗旧数据。我曾经帮一个项目迁移,ACL表里有10万条“张三 → 文档X → 读取”这样的记录,需要合并成角色。我写了个脚本按用户聚类,结果发现同一个用户在不同文档上权限不一致——压根不能简单归类。最后只能找业务方一个个确认。嗯,这种脏活比设计模型累多了。