角色说明你是谁,能力说明你能做什么,混在一起就会失控。
一、一个 Member 删掉了整个工作区
一位客户的项目经理在试用周岚的协作工具,角色是 Member。某天他在「工作区设置」页看到一行「示例项目」,右侧有一个垃圾桶图标。他以为删的是这个示例项目,弹窗只写了「删除后不可恢复」,他点了确认。
系统执行的是工作区级联删除:工作区、3 个项目、47 份导出、2 个 API key 进入待删除队列,30 分钟后硬删。他直到收到「工作区已删除」的邮件,才意识到自己删的不是一行,而是整个租户。
事后查权限表,问题很清楚:旧模型把「删除」当成一个不分资源粒度的动作,只要角色是 Member 就拥有 delete,而删除按钮绑定的对象是工作区。按钮没有告诉他作用域,权限也没有拦住他。
以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。
他不是点错了按钮,而是系统没有告诉他「这个按钮删的是什么」。
权限矩阵的第一作用不是限制人,而是让每个动作的作用域可见。角色名称是给人看的,动作与资源的组合才是给系统执行的;两者不写清楚,用户只能靠猜。
角色名也不可靠。「Member」在十个产品里有十种含义,有的能删项目,有的只能看;真正可核对的是「这个角色对这个资源能做哪几个动作」。
所以本文先定义四个角色与它们的禁区,再把 8 个资源、4 个动作摊成一张表,最后用 128 格复算说明为什么只允许 43 格。
二、四个角色:定义、禁区与典型误用
角色越少越好,但每个角色必须有明确的「不能做什么」。
| 角色 | 一句话定义 | 不能做什么 | 典型误用 |
|---|---|---|---|
| Owner | 工作区的最终负责人,承担账单与合规责任 | 不能移除最后一位 Owner;不能绕过审计 | 把 Owner 当日常账号,人人都是 Owner |
| Admin | 日常管理者,能配置工作区和管理成员 | 不能改支付方式(除非授予 Billing);不能删除工作区 | 把 Admin 当 Owner 的复制品 |
| Member | 能创建和修改自己负责的项目内容 | 不能管理成员、账单、API key;不能删除工作区 | 把 Member 当只读,或当管理员 |
| Viewer | 只读参与者,用于客户、审计和外部顾问 | 不能创建、修改、删除任何资源;不能被授予 Billing | 给 Viewer 发编辑链接,或用共享账号代替 |
Billing 不是第五个角色,而是一项可以单独授予的能力;它可以给 Admin,也可以给不碰项目的财务同事。
为什么不是五个角色?每加一个角色,矩阵就多 32 格,解释成本翻倍。用能力补场景,不要用角色补场景;角色负责「人在团队里的位置」,能力负责「这个人额外能做哪件特殊的事」。
Owner 至少 2 人。一个人离职、失联或注销,唯一 Owner 的工作区就会锁死;第 09 篇把这条写成硬规则。但也不能人人 Owner,2 到 3 人足够,多了等于没有最终负责人。
Admin 的边界要写死:能邀请和停用成员,但不能移除成员,也不能修改 Owner 角色;移除成员与修改 Owner 角色需要另一位 Owner 确认。这条双人规则挡的不是恶意,而是误操作和账号被盗。
Member 的边界依赖资源归属,不只是角色。他能归档自己创建的项目,不能归档别人的;这要求数据行上有 owner_id,而不是只查角色。没有资源归属,矩阵只能写到「Member 能删项目」这种粗粒度。
Viewer 上限 10 人,与第 08 篇的席位口径呼应。Viewer 免费、不占付费席位,但仍受 10 人上限约束;超过 10 人时应该走只读导出或客户门户,而不是继续加人。这个上限控制的是支持成本和数据暴露面。
三、8 资源 × 4 动作:把允许写成格子
下表是策略视图;每个格子写「全 / 部分 / 无」,并在括号里写例外。
| 资源 | Owner | Admin | Member | Viewer |
|---|---|---|---|---|
| 工作区设置 | 部分(查看、修改、删除) | 部分(查看、修改) | 无 | 无 |
| 成员 | 全(含移除) | 部分(查看、邀请、停用) | 无 | 无 |
| 账单 | 部分(查看、改支付方式) | 无(除非单独授予 Billing) | 无 | 无 |
| 项目 | 部分(查看、创建、修改;不物理删除) | 部分(查看、修改) | 部分(查看、创建、修改自己的) | 部分(只读) |
| 导出 | 部分(查看、创建) | 部分(查看、创建) | 无 | 部分(只读) |
| API key | 全 | 部分(查看、创建) | 无 | 无 |
| 审计日志 | 部分(只读) | 部分(只读) | 无 | 无 |
| 集成 | 全 | 部分(查看、创建、修改) | 无 | 部分(只读) |
矩阵的价值不在「允许」,而在「无」和「部分」——它们逼你说出为什么不允许。
「部分」必须写清是哪几个动作。只写「部分」等于把解释权留给实现者,而实现者会按最宽松的理解写;三个月后,没人记得当初排除的是删除还是导出。
项目不物理删除,只归档。这样 Member 的「删除」变成可恢复的归档,误删不会变成数据事故;工作区删除单独走 Owner 双人确认加 30 天延迟,和项目归档不是一个动作。
导出是独立资源。能看项目不等于能导出;导出要单独授权并写审计,客户数据泄露多半发生在导出,而不是发生在查看。Member 默认没有导出,这是矩阵里最容易被销售挑战的一格。
审计日志只读,任何人不能改删,Owner 也只能看。保留期按合同,导出审计日志本身也要留痕;这一行故意最窄,因为它记录的是其他所有行的行为。
矩阵要落到代码。每个格子对应一个权限字符串,例如 project:update;UI 隐藏按钮不等于拒绝,第 05 篇讲的三层校验从 API 层开始。矩阵是策略,判定函数是执行,两者不能只做一半。
默认拒绝。未列出的动作一律拒绝;新资源上线必须先加矩阵行,不能默认继承「和项目一样」,否则每加一个功能就多一组没人审过的权限。
四、128 格复算:为什么只允许 43 格
把矩阵当成一张 4 × 8 × 4 的表来数,避免「看起来差不多」。
角色 4 × 资源 8 × 动作 4 = 128 格
Owner 22 + Admin 15 + Member 3 + Viewer 3 = 43 格
43 ÷ 128 = 33.6%
默认拒绝:128 − 43 = 85 格
「部分」只按括号内列出的动作计数
Viewer 上限 10 人
Owner 至少 2 人
43 格不是目标比例,而是逐格判断后的结果;如果你的矩阵一算就是 90 格,说明「部分」写得太松。
为什么 Owner 不是 32 格?工作区没有创建,账单没有创建和删除,导出没有修改和删除,API key 没有修改,审计日志只有查看,项目不做物理删除;不适用不等于拒绝,但也不计入允许,所以 Owner 是 22 格。
为什么 Admin 只有 15 格?工作区删除、项目删除、成员移除、API key 删除、集成删除和账单,都留给 Owner 或 Billing 能力;Admin 做日常,不做不可逆。不可逆动作集中到少数人,审计才有意义。
Member 的 3 格是查看、创建、修改自己的项目。不能导出、不能管成员、不能碰 API key;这不是不信任,而是把「能做什么」压到与他的工作直接相关的最小集合。
Viewer 的 3 格是项目、导出、集成只读。不能看成员、账单、API key 和审计日志;客户和外部顾问需要看结果,不需要看组织内部结构。
Viewer 上限 10 与 Owner 至少 2 是两个不同方向的约束:前者控制席位与支持成本,后者保证可用性。两个数字都要写进开通检查,而不是等出事再补。
矩阵变更要有流程。加一格要写理由、申请人、复核人和到期日;季度复核一次;员工离职或换岗时按角色回收能力,而不是逐个资源去猜。
五、行动清单与复算验收
先把角色写清楚,再把矩阵填满,最后数一遍格子。
- 写下四个角色的一句话定义和「不能做什么」
- 把 Billing 从角色里拆出来,做成可单独授予的能力
- 列出自己产品的资源清单,逐行填 8 × 4 矩阵
- 每个「部分」写清具体动作和例外条件
- 把项目删除改成归档,工作区删除加双人确认和延迟
- 导出单独授权并写审计,不随项目查看权限自动获得
- 数一遍允许格数,和 43 对比,解释每一处差异
- 设定 Owner 至少 2 人、Viewer 上限 10 人的开通检查
验收标准:你能否拿出自己产品的权限矩阵,指出总格数、允许格数和每一个「部分」的具体动作;做不到,说明矩阵还停在角色名称上。
使用边界与实操验收
本文矩阵是 RBAC 基线,不覆盖 ABAC、ReBAC 和字段级权限;资源粒度不同,格数会变。
矩阵是起点,不是授权系统的全部;把它当全部,会在第一个跨组织协作需求上崩掉。
RBAC 管粗粒度,ABAC 管属性,ReBAC 管关系。三者可以叠加,不要用一个打天下;Google Zanzibar 走的是关系路线,适合文档继承和跨组织共享,但实现成本远高于四角色矩阵。
字段级权限不在矩阵里。「查看项目」不等于「看所有字段」,成本、合同金额、个人信息可能需要单独授权;这一层要落到序列化,而不是按钮。
跨组织协作时,角色要带作用域。同一个人在 A 工作区是 Admin,在 B 工作区可能只是 Viewer;把角色挂在用户上,换一个工作区就会失效。
矩阵要能导出成人类可读的文档。客户的安全问卷会问「你们有哪些角色、各自能做什么」,不能只回答「代码里有」;文档与代码不一致时,以代码为准并修文档。
从旧权限迁移到新矩阵时,先开影子模式比对拒绝日志,再切换。直接切换会把原本合法的操作一起锁死,客户只会看到「突然不能用了」。
关键参考与核验范围
核验日期:2026-10-25。以下链接用于核对角色、授权与关系模型的一般做法,本文未逐条引用其内容。
- OWASP Authorization Cheat Sheet :用于核对默认拒绝、最小权限与集中判定的表述。
- NIST RBAC :用于核对角色、权限、用户与角色分配的基本模型。
- Google Zanzibar 论文页 :用于核对关系型授权与跨资源继承的思路。
- OWASP ASVS :用于核对访问控制的验收条目与测试范围。
引用口径。 本文只借用这些材料讨论的一般模型,不引用具体条款编号;四角色、8 资源、43 格与 33.6% 均为本文的教学设定。
核验范围。 覆盖角色定义、资源动作矩阵、允许格数复算与 Owner/Viewer 约束;不覆盖 SSO、SCIM、字段级权限和具体合规认证。
如何自行复核。 拿一张纸列出自己产品的资源与动作,按四角色逐格填「全 / 部分 / 无」,数出允许格数;再对照本文的 43 格,逐条解释多出或缺少的格子。
系列导航
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。