权限中心的工程落地:架构、缓存、一致性与高可用

权限模型正确不代表系统能够在生产环境稳定运行。微服务每个请求都远程调用权限中心会增加延迟和单点依赖;把全部权限放进 JWT 又会导致撤销延迟、Token 膨胀和动态策略失真。

工程落地需要在一致性、性能、可用性和可解释性之间做明确取舍。

1. 权限中心与业务系统的边界

权限中心负责:权限目录、角色、授权关系、策略、版本、决策接口和授权审计。

业务系统负责:资源状态、金额、客户归属、领域状态机、数据查询和最终事务。权限中心不复制完整业务数据库,也不能成为所有业务规则的脚本平台。

身份系统负责认证和凭证,组织系统负责员工与部门事实源。权限中心保存引用、必要快照和版本。

2. PAP、PDP、PEP、PIP 的部署

PAP 通常位于控制面,用于管理角色、策略和发布版本;PDP 可以是中央服务、Sidecar 或进程内库;PEP 分布在网关、Controller、Service、Repository 和消息消费者;PIP 从组织、业务、设备和风险服务获取属性。

决策接口应稳定统一:

{
  "actor": "U1006",
  "principal": "U1006",
  "subject": "U1001",
  "tenant": "T1001",
  "resource": {"type": "ORDER", "id": "O1001"},
  "action": "sales:order:read",
  "context": {"impersonationSession": "IMP-1001"}
}

返回:

{
  "decision": "ALLOW",
  "reasonCode": "ALLOW_ROLE_PERMISSION",
  "effectiveScope": {"type": "SELF"},
  "obligations": [],
  "permissionVersion": 42,
  "policyVersion": 12
}

3. 三种运行模式

权限决策部署模式

远程实时决策

优点是策略集中、撤销快、解释统一;缺点是每次调用增加网络延迟和中央依赖。适合高风险、低频、动态属性多的操作。

本地快照决策

控制面下发角色、ACL、策略或编译快照,业务服务本地判断。性能和可用性好,但需要版本、签名、失效和差异检测。

混合模式

常见选择:静态功能权限和低风险读本地判断;付款审批、跨租户管理和临时提权远程判断;数据权限在业务服务的 Repository/数据库执行。

4. 批量决策

菜单渲染和列表操作不应对每个按钮或每个资源发一次远程请求。权限中心应支持:

  • 多 Action Check;
  • 多资源 Check;
  • List Objects;
  • List Users;
  • 数据过滤条件或授权索引。

批量接口必须限制请求规模、超时和结果版本,避免成为新的性能和数据枚举入口。

5. 缓存分层

可分别缓存:

  • 角色权限集合;
  • 角色继承闭包;
  • 主体有效 Role Assignment;
  • 用户组和组织成员;
  • ACL 局部结果;
  • 策略编译结果;
  • 稳定属性;
  • 最终决策。

最终决策缓存最危险,因为结果可能受金额、时间、设备和资源状态影响。不能只使用 userId + permissionCode

缓存与版本

缓存键或缓存条目至少应关联 tenant、subject、application、resource、action、context 摘要、permissionVersion 和 policyVersion。

6. 版本体系

需要区分:

  • permission_version:权限项元数据;
  • role_version:角色权限、层级和约束;
  • assignment_version:授权关系;
  • principal_permission_version:主体有效权限汇总;
  • policy_version:策略内容;
  • tenant_change_sequence:租户内变更序号;
  • snapshot_version:下发快照。

不要把所有变化压成一个难以解释的 version。高风险请求应验证主体权限版本达到控制面要求的最低线。

7. 变更传播

权限撤销传播

基本流程:事务内更新授权状态和 Outbox 事件;消息系统发布变更;业务节点按版本幂等处理;失效缓存并按需拉取新快照。

需要处理:

  • 消息丢失:版本轮询或补偿拉取;
  • 消息重复:按事件 ID 和版本幂等;
  • 消息乱序:忽略旧版本;
  • 节点离线:恢复后比较租户序号;
  • 快照回滚:拒绝低于最低安全版本的快照。

权限撤销通常比授予更敏感。可对高风险撤销维护快速黑名单或在线版本检查,缩短缓存窗口。

8. Token 中放不放权限

完整权限放入 Token

优势:本地判断、低延迟。问题:角色多时 Token 很大,资源 Scope 和 ABAC 难表达,权限撤销只能等 Token 过期或维护额外状态。

Token 只放身份

权限实时,但每次都依赖权限查询。

推荐混合

Token 放稳定身份、tenant、会话、认证强度和 permission_version;业务服务使用本地缓存或权限中心加载有效权限。短期、低风险的粗粒度 Scope 可以进入 Token,但不能把 Token 当作唯一授权事实源。

9. 服务身份和用户身份传播

服务身份传播

order-service 调用 finance-service 时至少有两层身份:调用服务是谁,以及它代表哪个用户。下游不能只信任一个可伪造的 X-User-Id

可使用:

  • mTLS/Workload Identity 验证服务;
  • 签名 Token 验证用户;
  • Token Exchange 或 On-Behalf-Of 令牌;
  • 明确 audience、scope、actor 和 subject;
  • 下游同时检查服务调用权限和用户业务权限。

服务自身没有 finance:payment:approve 时,即使代表财务主管,也不能调用审批工具;反之,服务有能力也不能绕过用户权限。

10. 非人主体凭证

API Key、Client Secret、证书和私钥必须与 Principal 分开管理,存入专门密钥系统。建议使用短期工作负载身份,避免长期静态密钥。

每个凭证需要:状态、颁发时间、到期、最后使用、轮换策略和吊销。删除凭证不等于删除主体,撤销权限也不等于轮换密钥,两种生命周期要分别处理。

11. 多租户工程隔离

隔离维度包括:

  • 数据库查询;
  • Redis Key 和本地缓存;
  • 搜索索引;
  • 消息 Topic/事件字段;
  • 对象存储路径与签名 URL;
  • 决策日志和指标;
  • 权限快照;
  • 管理入口和平台管理员上下文。

必须在每层做显式检查,不能指望最外层网关传入的 tenant 永远正确。

12. 高可用与降级

权限中心超时时默认拒绝,但可以按风险使用有效本地快照:

  • 高风险审批、角色分配、模拟用户:无法验证最新版本时拒绝。
  • 低风险读取:快照签名有效、未过期且版本高于最低线时可继续。
  • 审计服务异常:高风险强制审计操作拒绝;低风险操作仅在可靠本地缓冲可用时继续。
  • 属性服务异常:必需属性缺失拒绝,可选属性使用安全默认值。

降级策略要按 Action 配置和测试,不能在故障时临时决定“先放行”。

13. 可观测性

建议指标:

  • PDP P50/P95/P99 延迟;
  • Allow/Deny/Indeterminate 比例;
  • Deny 原因分布;
  • 各层缓存命中率;
  • PIP 调用失败和延迟;
  • 权限变更传播延迟;
  • 节点策略版本分布;
  • 快照过期和降级次数;
  • 高风险权限使用量;
  • 通配符和跨租户特权调用。

日志必须包含 traceId、requestId、Actor、Subject、resource、action、reasonCode 和版本,避免只记录“403”。

14. 灰度迁移

旧权限系统迁移到新 PDP 时,可以使用双轨决策:旧系统负责真实结果,新系统 Shadow 计算并记录差异。先覆盖低风险读,再迁移写和高风险操作。

差异要按原因分类:模型数据缺失、Scope 不一致、策略语义不同或旧系统本身存在越权。不能为了追求结果一致,把旧漏洞复制到新系统。

15. 开源方案定位

  • Spring Security:Java 应用内认证与授权基础,适合 HTTP、方法权限和扩展 AuthorizationManager。
  • Casbin:多语言访问控制库,模型与策略可配置,适合应用内执行。
  • OPA:通用策略引擎,使用 Rego,适合策略即代码和多基础设施场景。
  • OpenFGA:Zanzibar 风格关系授权,适合 ReBAC、Check/List Objects。
  • Cedar:面向授权的策略语言,强调 principal/action/resource/context 和策略验证。
  • Keycloak Authorization Services:在身份平台上提供资源、Scope、策略和集中 PDP。

选型前要先确定问题是认证、角色管理、动态策略还是关系授权,不能因为产品都写着“Authorization”就认为可以互换。

16. 推荐架构

小型单体

Spring Security + 本地 RBAC + Repository 数据权限;ACL 仅在有分享需求的资源中实现。

中型多系统

统一权限目录和治理中心,Role Assignment/Policy 集中管理,权限快照分发到业务服务,高风险请求远程决策。

大型平台

控制面与数据面分离;关系授权、策略决策和数据权限各自使用适合的执行组件;版本化快照、全链路审计、灰度策略和故障演练成为基础能力。

17. 常见错误

  • 每个请求都同步远程鉴权,没有缓存和降级边界。
  • 把所有权限塞入长寿命 JWT。
  • 缓存失效只依赖 Pub/Sub,消息丢失后永久陈旧。
  • 服务间只传用户 ID,不验证服务身份和代理权限。
  • 多租户只在数据库隔离,Redis 和搜索索引共用 Key。
  • 权限中心复制全部业务数据,形成新的单体和数据一致性问题。
  • 只监控 5xx,不监控错误 Deny、版本分裂和撤销延迟。

18. 小结

权限中心的关键不是“提供一个 hasPermission API”,而是管理事实源、版本、传播、执行和故障边界。正确的模型必须通过稳定的运行时架构才能真正成为安全边界。

参考资料