系统设计 / 访问控制 · 从 RBAC 查表到 policy 判定函数 / AllowedScope:同一个 action,对谁做 待审核 3 / 23
Scope · 对谁做

AllowedScope:同一个 action,对谁做

Permission 回答「能不能做」,Scope 回答「对谁做」。这是两个正交的维度。仅有 order:read(见 Permission 的身份)还不够——能读所有人的订单,和只能读自己的,是两种完全不同的权力。区分它们的就是 AllowedScope(数据范围),常见五档按权限由宽到窄是 FullGroupSelfPublicNone

1 · 各 scope 下的可见行

每个 scope 对应一条过滤条件:Full 无过滤,Group 比对 row.groupSelf 比对 row.ownerPublic 只放行公开行,None 恒不可见。

图 1-1 · 同一张订单表在五种 scope 下的可见行。可切换 scope,观察过滤条件与可见行数的变化。

2 · 两个轴不要混为一谈

把「能不能做」和「对谁做」拆开,授权就清晰了。同一个 action 配不同 scope,每格是一种真实的权力:

表 2-1 · 三条 action 分别配三种 scope 得到的权力。
能力 (action) @ Self @ Group @ Full
article:update 改自己的文章 改本组的文章 改所有文章
order:read 看自己下的单 看本组负责的单 看全平台的单
order:cancel 取消自己的单 取消本组的单 取消任意单

建议 ·「客服只能退本组的单」「作者只能删自己的稿」这种需求,不该靠创建新角色来解决,而是同一条 permission 配不同 scope。混淆这一点,是权限系统失控的首要原因。

3 · Scope 的取值

  • Full — 全部数据行,不限 owner / group。
  • Group — 同部门/团队:row.group === me.group
  • Self — 仅自己创建/拥有的:row.owner === me.id
  • Public — 仅标记为公开的只读数据。
  • None — 什么都看不到,等于没有这条 permission(占位/显式关闭用)。

这五档按权限排序,不是一条集合包含链。真正互相包含的只有前三档(FullGroupSelf);Public 是一道正交的过滤条件——图 1-1 里它唯一放行的那行归隔壁组的人所有,SelfGroup 都看不到。按「PublicSelf 的子集」去实现 WHERE 条件会漏掉公开数据。

警示 · Scope 是数据层的事。「能不能进这个页面」UI 能拦;但「这页里到底返回哪几行」必须在查询时按 scope 加 WHERE 条件——否则前端隐藏的行,直接调用 API 就能全部取到。这条约束由 Server 层Repository 落实。