Capability Systems · 01 / 18
身份与权限
从身份可信,到权限可控
01 · 一句话建立认知身份与权限系统先证明请求者是谁,再根据组织、成员关系、资源和当前条件决定能否操作,并保证撤权及时生效、每次决策可以追溯。
架构总览
先看懂系统,再学习局部
四张图依次回答边界、组成、运行和变化;图中的每条连线都代表职责或数据流。
业务与领域架构
它要回答:身份与权限系统管理哪些业务对象,它的边界在哪里?
同一 User 在 Organization B 可以拥有另一条 Membership,并仅拥有 Viewer 角色。
技术组件架构
它要回答:这套系统由哪些技术组件组成,认证、授权和业务数据分别由谁负责?
认证、授权与业务服务分别发出审计或变更事件,不用同步调用绑死主链路。
核心运行链路
它要回答:一次用户访问如何从登录走到最终允许或拒绝?
- 01登录Web / App → IdP
- 02身份验证密码 · SSO · MFA
- 03Session / Token携带可信 subject
- 04Gateway · PEP验签、过期、路由
- 05Business · PEP在 Tenant 内加载资源
- 06PDP读取事实并计算策略
- 07Allow / Denyreason · policy_version
- 08执行与审计仅 Allow 执行;两种结果都留证
Gateway 可以拒绝无效 Token,却不知道 p_42 是否属于 t_01;业务服务必须先加载可信资源,再让 PDP 判断。
权限变更与数据一致性
它要回答:用户被禁用、降级或撤权后,旧 Token 和旧缓存如何停止放行?
提交事实后,通过事件让所有副本最终收敛。
- 01管理操作Admin → Member
- 02DB 事务Membership + Outbox
- 03Event Bus至少一次投递
- 04幂等消费忽略旧 version
- 05缓存失效tenant + subject
- 06Token Versionv37 < v38
- 07服务刷新后续请求重新决策
- 08审计与告警积压 · 重试 · 失败
高风险操作不能等待缓存 TTL 或消息积压。
名词地图
只解释刚才图中出现的对象
桌面端将鼠标移入即可查看简短解释;触屏端直接展示,不需要先点击展开。
真实业务场景
员工已被降级,却仍尝试删除项目
用同一个请求验证业务边界、组件职责、运行决策和撤权一致性。
这条线对应图四的数据一致性链路。
- 数据 · 管理操作管理员将 u_17 从 Admin 降为 Member
数据库事务同时更新 Membership,并写入 authz.version=38 与 Outbox。
- 数据 · 事件传播缓存失效事件开始传播
消费者按版本幂等处理,使 u_17:t_01 的权限缓存失效。
- 证据 · 审计记录谁撤销了什么权限
保存操作者、目标成员、旧值、新值、请求 ID 和发生时间。
这条线对应图二和图三的组件与运行链路。
- 技术 · Gateway旧 Token 签名仍然合法
网关确认 subject=u_17,但不会信任 Token 中旧的 Admin 声明作为最终权限事实。
- 业务 · Service PEP只在 t_01 内加载 p_42
查询同时包含 tenant_id 和 resource_id,先阻断跨租户 IDOR。
- 运行 · PDP发现缓存版本低于 v38
刷新 Membership 后,Member 已不具备 project:delete,决策为 Deny。
- 结果 · 证据403 Forbidden · missing_permission
不执行业务删除;记录 actor、tenant、resource、action、reason 和 policy_version。
细节设计
每一段只解决一个设计问题
建立全局地图之后,再下钻到事实、契约、安全、可靠性和验证。
为什么 User 和 Membership 必须分开?
同一个人可以属于多个组织,并在每个组织拥有不同状态与角色。
| 对象 | 保存什么事实 | 建议关键字段 | 关系与约束 |
|---|---|---|---|
| User | 全局主体 | id, status, profile | 1:N Identity;1:N Membership |
| Identity | 可用于登录的身份 | provider, subject, credential_ref | provider + subject 唯一 |
| Tenant | 组织与数据隔离边界 | id, type, status | 1:N Membership;1:N Resource |
| Membership | 用户进入组织的关系 | user_id, tenant_id, status, authz_version | 连接 User、Tenant、Role |
| Role | 权限的业务化集合 | tenant_id, name, version | M:N Permission;授予 Membership |
| Permission | 最小能力声明 | resource_type, action | 例如 project:delete |
| Policy | 带条件的判断规则 | effect, condition, version | 组合主体、资源、动作与 Context |
| Resource | 被保护的业务对象 | id, tenant_id, owner_id, attributes | 查询必须携带 tenant_id |
| AuditEvent | 不可抵赖的决策证据 | actor, tenant, resource, action, result | 追加写;关联 request_id 和 policy_version |
权限判断应该放在网关、业务服务,还是独立授权服务?
答案不是三选一,而是把粗控、资源事实和策略计算放在正确的位置。
验签、过期、基础 scope、限流和路由;不知道资源真实归属。
在 Tenant 内加载资源,发起授权请求,并执行 Allow 或 Deny。
组合成员、角色、权限、资源属性和环境,返回原因与策略版本。
{
"subject": "u_17",
"tenant": "t_01",
"action": "project:delete",
"resource": { "type": "project", "id": "p_42", "owner": "u_09" },
"context": { "risk": "normal", "authn_level": "mfa" }
}{
"decision": "deny",
"reason_code": "missing_permission",
"policy_version": 38,
"decision_id": "dec_7k2",
"ttl_ms": 15000
}怎样避免一次普通查询穿透组织边界?
- 主体和 Tenant 从可信会话或路由上下文取得,不接受客户端自报角色。
- 资源查询同时包含
tenant_id与resource_id。 - 数据库约束、索引、缓存键和对象存储路径都包含 Tenant。
- 返回 404 或 403 时,不泄露其他租户资源是否存在。
- 跨租户管理能力单独建模,限时、双人审批并全量审计。
什么时候使用 Token、RBAC,什么时候增加更多复杂度?
可撤销 Session 或短 Token,优先降低失效窗口。
短 Token 传递身份,当前权限仍由服务端重新判断。
先用少量 RBAC 角色覆盖主要工作职责。
条件真实出现后,再用 ABAC Policy 表达。
PDP、缓存或消息系统不可用时,应该允许还是拒绝?
降级策略必须按动作风险设计,不能用一个全局开关决定。
| 故障或异常 | 敏感写操作 | 低风险读取 | 必须记录 |
|---|---|---|---|
| PDP 超时 | 默认拒绝;返回可重试错误 | 仅在有短期已验证决策时有限降级 | timeout、action、fallback |
| 缓存不可用 | 查询权威数据或拒绝 | 回源并限制并发 | cache_miss、latency |
| 事件积压 | 版本不一致时实时检查 | 缩短缓存 TTL | lag、old_version、consumer |
| 审计写入失败 | 高风险操作阻断或写入本地可靠缓冲 | 进入可靠重试 | decision_id、retry_count |
如何证明某次操作当时确实被授权?
审计事件、指标、追踪和测试需要共享同一个 decision_id。
actor · tenant · resource · action · result · reason · policy_version · request_id · decision_id
授权延迟、拒绝率、缓存命中率、过期版本命中、事件积压、紧急封禁次数
角色组合、资源归属、Tenant 穿透、撤权延迟、重放、PDP 超时、审计完整性
方案取舍与失败模式
选择必须写明条件,底线必须能够测试
没有通用赢家;风险、规模、延迟和团队能力共同决定方案。
| 选择 | 偏向左侧,当 | 偏向右侧,当 | 稳妥起点 |
|---|---|---|---|
| Session vs Token | 管理端 Web、即时注销 | 跨服务、开放 API、移动端 | 可撤销 Session;短 Token + 刷新机制 |
| RBAC vs ABAC | 岗位稳定、权限组合有限 | 依赖归属、金额、地区或风险 | RBAC 起步,真实条件出现后叠加 ABAC |
| 集中 PDP vs 服务内判断 | 多服务需统一策略和审计 | 强领域事实只能由本服务理解 | 集中 PDP,业务服务保留资源级 PEP |
| 实时查询 vs 权限缓存 | 高风险写操作、撤权必须即时 | 读多写少、授权事实稳定 | 短 TTL + 版本号 + 主动失效 |
| 自建认证 vs 外部 IdP | 合规边界特殊且有安全团队 | 要快速支持 SSO、MFA 和联合登录 | 优先购买认证能力,自建业务授权 |
| Fail-open vs Fail-closed | 低风险读取且有安全兜底 | 写操作、管理操作、跨租户请求 | 敏感操作默认拒绝,按风险设计有限降级 |
只在前端隐藏按钮
会发生直接调用接口仍可越权
设计底线所有敏感动作在服务端授权
查询资源时没有 Tenant ID
会发生跨组织数据泄露
设计底线tenant_id 进入查询条件、索引和审计
信任客户端传来的角色或资源归属
会发生修改参数即可冒充权限或读取他人资源
设计底线从可信会话取主体,并在租户内加载资源
撤销角色后旧 Token 继续有效
会发生离职或降权后仍有访问窗口
设计底线短生命周期、版本校验和主动撤销
角色数量不断膨胀
会发生角色变成用户级例外,无法治理
设计底线稳定岗位用 Role,差异条件用 Policy
权限服务故障时全部放行
会发生局部故障演变为系统性越权
设计底线按动作风险设置超时、降级和默认拒绝
审计字段不完整或可被覆盖
会发生事后无法还原当时为何授权
设计底线追加写并保存主体、资源、结果、原因和策略版本
最小落地路径
从边界和事实开始,按风险逐层补齐
第一天不需要通用策略平台,但第一天就要守住租户和服务端授权。
- 01
画出租户边界
列出核心资源、敏感动作,以及必须按组织隔离的数据。
- 02
接入身份能力
优先使用成熟 IdP,建立 User、Identity 和 Membership。
- 03
用少量 RBAC 起步
让稳定岗位对应 Role,让 Role 聚合最小 Permission。
- 04
统一服务端授权
建立 authorize() 契约,在业务服务加载资源后执行 PEP。
- 05
补齐撤权与证据
加入版本、主动失效、追加式审计和安全测试。
- 06
按真实复杂度演进
需要多服务和条件规则时,再加入事件传播、缓存和 ABAC。
你是我的 B2B SaaS 身份与权限架构师。请根据以下产品信息设计一套可落地的身份权限体系: 产品与核心资源:【填写】 用户类型与组织结构:【填写】 需要支持的登录方式(密码 / SSO / MFA 等):【填写】 高风险动作与合规要求:【填写】 技术栈、规模与延迟目标:【填写】 请先指出缺失的关键上下文,再按以下顺序输出: 1. 划定 Tenant 边界,并定义 Subject、Resource、Action、Context; 2. 给出 User、Identity、Tenant、Membership、Role、Permission、Policy、AuditEvent 的关系与关键字段; 3. 设计认证链路、服务端授权入口,以及网关粗粒度 / 业务服务细粒度的职责边界; 4. 先给最小 RBAC 方案,再说明何时需要 ABAC,避免角色爆炸; 5. 说明权限变更后的 Token、Session、缓存失效和一致性策略; 6. 用“管理员降级后尝试删除项目”走一遍 Allow / Deny 与审计流程; 7. 列出越权、租户穿透、撤权延迟和审计缺失的威胁模型与测试清单。 每个关键选择都要写明适用条件、代价和默认建议;不要只列术语,也不要假设前端隐藏按钮能够提供安全性。
复制提示词如果明天要支持第一家企业客户,