第二章 权限模型基础:概念、ACL、RBAC、ABAC

权限模型这东西,说白了就是回答两个问题:谁能对什么资源做什么操作。我刚入行时总觉得这玩意儿简单,不就是建个表存权限吗?直到被线上事故教育了几次,才明白选错模型多要命。这一章咱们把几个经典模型掰开揉碎,看看它们各自长什么样、用在哪儿、又死在哪儿。

2.1 权限模型的三要素

不管什么模型,核心骨架都一样。你想想看,任何一个权限判断都能拆成三部分:

  • 主体(Subject)——谁要做事。用户、角色、服务账户都算。
  • 资源(Resource)——对什么东西做事。文件、API、数据库记录都是资源。
  • 操作(Operation)——做什么事。读、写、删除、执行,各系统自己定义。

整个权限模型的演进史,就是不断给这三者之间加“缓冲层”和“条件”的过程。嗯,记住这个视角,后面看模型会更清楚。

我的经验: 在金融系统里,资源往往不是单纯的“表”或“接口”,而是“客户资产数据”这种带业务语义的实体。你得先跟业务方把三要素对齐,否则模型搭出来也是废的。

2.2 ACL – 访问控制列表

ACL 是最直白的模型。它直接列出一张表:某主体 → 某资源 → 允许/拒绝某操作。Unix 文件权限就是个经典例子:

# 文件 /etc/passwd 的 ACL(简化)
用户 root: rw-
用户 alice: r--
所有人: r--

优点很明显:精确、灵活,每个资源能单独控制。但一旦资源多、用户多,这张表膨胀得比你想象快得多。我在一个电商后台见过 ACL 表超过 1 亿行,查询一次要扫全表……那场面,简直灾难。

避坑指南: 我曾经在给一个 CMS 系统做权限时,直接用 ACL 管理每篇文章的编辑权限。上线两周后,运营团队新增了 20 个角色,ACL 表每天新增几万行。DBA 直接找我“喝茶”。记住:ACL 适合资源少、主体少、权限变化慢的场景,比如文件系统、单机资源。

ACL 的数据模型大概长这样:

主体 资源 操作 效果
Alice文档-001读取允许
Bob文档-001写入允许
Bob文档-002读取允许

注意:每个主体-资源对都得一条记录。一旦资源上万,主体上千,ACL 表的行数就是千万级。

2.3 RBAC – 基于角色的访问控制

RBAC 加了一层“角色”。你不直接给用户分配权限,而是把权限捆成角色,再把角色给用户。你想想看,这不就是现实公司的做法吗?你是开发 -> 拥有 git push 权限;你是测试 -> 拥有 bug 管理权限。一句话:用户-角色-权限三层结构。

RBAC 有四个核心要素:

  • 用户 – 系统账号
  • 角色 – 职责集合,比如“管理员”、“编辑”
  • 权限 – 资源+操作
  • 会话 – 用户激活的角色组合(NIST RBAC 标准里强调的)

NIST RBAC 标准把模型分了三层:

层次 说明 典型用例
扁平 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 把权限判断变成了规则引擎。

避坑指南: 我曾经在一个 SaaS 产品里尝试全面 ABAC,结果策略数量超过 200 条,而且运维人员根本看不懂 JSON 格式的策略。后来我们把 80% 的通用规则降级成 RBAC,只对少数跨租户场景用 ABAC。一句话: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 打补丁。

我的习惯: 在新项目里先画一张“权限热力图”,标出哪些资源权限变化频繁、哪些受外部环境约束多。变化频繁的区域优先考虑 ABAC,稳定区域用 RBAC。别一开始就上 ABAC,除非你明确知道未来一年内会有 10 条以上的动态策略。
权限模型核心逻辑图 权限模型三要素 主体 (Subject) 资源 (Resource) 操作 (Operation) ACL 直接映射主体→资源 精确但膨胀快 适合小规模静态 表行数 = 主体数 × 资源数 RBAC 引入角色缓冲层 支持继承和约束 企业级首选 角色数可控,管理成本低 ABAC 基于属性策略引擎 动态灵活 适合复杂环境 策略可测性要求高

这张图把三要素和三个模型的关系串起来了。你可以看到:ACL 直接从主体到资源,没有中间层;RBAC 在中间加了角色;ABAC 则把判断逻辑交给了属性规则。从左上到右下,灵活性递增,但可管理性递减。

2.6 从ACL到ABAC的演进路径

我见过不少团队是这么进化的:

  1. 阶段一:直接硬编码。 if (user == 'admin') { allow }。这种代码我当年也写过,后来维护起来想骂人。
  2. 阶段二:ACL表。 把所有允许关系写成数据库行。能用,但到几千用户后开始卡。
  3. 阶段三:RBAC。 抽象出角色,权限集中管理。这是大多数系统的成熟形态。
  4. 阶段四:ABAC混合。 在RBAC基础上增加属性策略,处理跨部门、多租户等复杂场景。

有个细节:从ACL切换到RBAC时,最痛的不是改代码,而是清洗旧数据。我曾经帮一个项目迁移,ACL表里有10万条“张三 → 文档X → 读取”这样的记录,需要合并成角色。我写了个脚本按用户聚类,结果发现同一个用户在不同文档上权限不一致——压根不能简单归类。最后只能找业务方一个个确认。嗯,这种脏活比设计模型累多了。

我的建议: 新系统直接从RBAC起步,哪怕一开始只有三个角色。ACL作为历史遗留兼容用,别当成主力。等到你发现“角色膨胀”(超过50个角色)的时候,再考虑引入ABAC做属性扩展,而不是推倒重来。