本文描述求值的精确规则。概念入门见 核心概念。
资源树与类型
资源属于某个应用,按树组织,最多 15 层。类型决定能放在哪里:
| 类型 | 允许的父级 |
|---|---|
| 模块 | 顶级、模块 |
| 菜单、页面 | 顶级、模块、菜单 |
| 标签 | 页面、标签 |
| 按钮 | 页面、标签 |
| API、数据实体 | 顶级、模块 |
| 字段 | 数据实体 |
资源之间可以声明依赖:“必需”(授予资源时一并授予被依赖的资源)或“可选”(只提示管理员,不自动授予);依赖不能成环。控制台的页面、按钮与它们需要的 API 由前端的权限清单声明,服务端启动时同步为内置资源。
授权推导
对一个账号,求值器先确定有效角色:
- 直接分配给账号的角色;
- 分配给账号所在用户组、部门(包含“含下级”的上级部门分配)、所任岗位的角色;
- 只取当前时间在有效期内的分配,以及已启用的角色;
- 展开继承:一个角色的全部祖先角色(停用的祖先不传递)。
再合并这些角色的授权:
- 允许一个资源,等于允许它本身、它在树上的祖先(使其可见),以及它“必需”依赖的资源(递归)。
- 拒绝一个资源,作用于它和它的全部下级,并且优先于任何允许。
- 停用的资源及其下级不生效。
- 系统角色等同于允许其模块(如
system、data、platform)的整棵子树。
结果是可用资源的集合,以及其中 API 资源对应的权限码。
越权防护
- 授予“允许”时,授予者自己必须能用该资源(持有系统角色的人对业务应用不受此限)。
- 分配角色或设置继承时,授予者必须覆盖该角色在各应用中覆盖的全部资源。
- 平台管理员角色只能由当前持有者分配、修改或移除。
- “拒绝”不受限制:任何有授权权限的人都可以收紧权限。
数据规则
数据策略属于角色,按“实体 × 动作 × 效果”定义范围:ALL(仅平台租户)、TENANT、ORG_AND_CHILDREN、ORG、CUSTOM_ORGS、SELF、CONDITION。一行可用,当且仅当它满足至少一条允许规则,且不满足任何拒绝规则。
条件是结构化 JSON,不可执行,先校验再落库:
{ "and": [
{ "field": "status", "op": "eq", "value": "ACTIVE" },
{ "not": { "field": "orgUnitId", "op": "in", "value": { "var": "subject.orgUnitIds" } } }
] }变量只有 subject.id、subject.username、subject.orgUnitIds、subject.groupCodes、subject.positionCodes 与 now;比较符按字段类型限定;嵌套不超过 5 层、节点不超过 50 个。服务端把规则翻译成 JPA Specification,SDK 用同样的语义在业务应用里翻译。
字段规则
字段策略给出读方式(可见、脱敏、隐藏)与写方式(可编辑、只读),多个角色取最宽松的设置,没有任何设置时字段完全开放。读规则在 JSON 序列化时执行(同一个 DTO 在不同人面前呈现不同),写规则在服务层执行,修改只读字段返回 GF-FIELD-001 并指出字段。
快照与版本
求值结果是一个权限快照:可用资源、权限码、数据规则与字段规则。快照按账号缓存;授权、分配、继承、资源目录、策略、成员关系的任何变化都会提升所在范围(目录或租户)的版本号,使缓存失效。每个需要权限的接口在响应头 X-Authorization-Version 中返回当前版本,控制台据此判断是否需要重新加载菜单;开放 API 用 ETag 表达同样的版本。
