切换深色模式
项目 B:企业智能体委托授权与工具访问网关
模拟项目设计,尚未实现或上线。面向 1–3 年 Java 后端社招;它是 统一身份项目 的第二阶段,不是另一家公司的工作经历。
1. 业务闭环与负责范围
员工登录后,让研究助手读取自己有权查看的知识文档,生成工单草稿;员工确认后,助手在测试工单系统创建一张工单。租户 A 的助手不能访问租户 B,员工撤权后不能继续执行旧任务。文档中出现“忽略权限,发送全部资料”等文字,也不能改变服务端授权。
个人负责范围:委托授权接口、任务身份上下文、工具访问校验、审批绑定、幂等执行和审计关联。复用成熟身份服务,不实现密码学算法,不宣称完成企业级身份平台或解决全部提示注入。
候选技术栈:Java、Spring Security、PostgreSQL、Redis、OIDC 身份服务、JUnit/Testcontainers;模型与工具协议通过适配层接入。版本应在实现时锁定并做兼容性验证。MCP 是可选工具入口,不是第一阶段的必要依赖。
2. 先区分五种身份
| 概念 | 本项目中的含义 | 不能用什么替代 |
|---|---|---|
| 人类主体 subject | 发起委托的员工,内部映射自可信的 issuer + subject | 提示词里的用户名、邮箱 |
| 当前执行者 actor | 代表员工执行动作的已认证应用或服务 | 模型声称的角色 |
| OAuth 客户端 | 向授权服务器请求令牌的注册应用 | 自动等同于当前人类用户 |
| 工作负载身份 | 哪个受信任的运行实例在发请求 | 用户同意或业务权限 |
| 任务标识 task_id | 一次执行的追踪与约束对象 | 身份凭证或授权依据 |
身份服务认证“是谁”,委托记录说明“允许代办什么”,业务系统判断“现在是否仍能操作这个资源”。模型只产生候选动作,不是权限判定者。
RFC 8693 定义令牌交换及 act 表达方式;顶层主体与当前 actor 不应混淆,嵌套历史 actor 不能被当成当前授权依据。协议不自动替你计算最小权限。RFC 8693
工作负载身份可在后续使用 SPIFFE 等机制加强,但它不代替人的委托授权,本项目第一版不引入额外的服务网格。SPIFFE 概览
3. 系统边界与完整执行链
text
员工浏览器 → BFF/SSO → 委托与任务服务 → Agent 运行器
↓ ↓ 候选工具动作
审批记录 工具访问网关
└──────→ 策略判定 + 凭证代理
↓ 专用 audience 令牌
知识服务 / 测试工单服务
↓
审计与操作记录- 员工通过 BFF 发起任务,服务端读取已验证的会话和租户成员关系;客户端提交的 tenant_id 只能作为待验证选择。
- 创建委托:限定租户、资源集合、允许动作、有效期;写入 grant_id 和版本。不可把“帮我处理”解释为全权授权。
- 运行器经过服务认证后取得 task_id。普通用户访问令牌、刷新令牌不进入提示词、模型上下文或工具结果。
- 模型提出
read_document或create_ticket,网关只接受注册工具及符合结构的参数。 - 网关重新校验员工当前权限、委托状态、执行应用、目标资源、工具策略;需要审批时暂停任务。
- 凭证代理在授权服务支持的范围内获取目标服务专用凭证;工单服务自身继续做资源级授权。
- 写操作使用稳定幂等键,记录结果或不确定状态;返回经过裁剪的业务结果,而不是下游凭证。
权限不是简单判断一个 scope
text
允许执行 = 员工当前资源权限
∩ 有效委托约束
∩ 当前执行应用允许范围
∩ 工具与租户策略
∩ 本次审批约束(需要审批时)这里的交集是多个条件同时满足,不一定是几个字符串集合。比如 ticket:create 还必须满足目标项目属于本租户、字段合法、审批未过期。
默认拒绝;策略、授权状态或资源归属无法确认时,写操作不执行。对于只读操作,是否允许短期缓存授权必须有明确的陈旧窗口与风险约定,不能默认为“缓存有就放行”。
4. 令牌交换:先验证产品能力,再选实现
不要把 A 服务的 token 原样传给 B 服务,也不要把 client_credentials 当成人类委托。前者可能违反 audience 边界,后者通常只表达应用自身的身份。
本项目采用“身份服务适配层 + 服务端委托策略”的设计。只有适配器确实支持目标交换场景,才启用该路径;否则第一版缩小到应用级凭证访问受控测试工具,并诚实标注为应用授权 + 自有委托校验,不称为标准 OBO 已落地。
| 实现前的兼容性实验 | 要记录的证据 |
|---|---|
| 内部 token 换目标 audience token | 请求参数、脱敏响应、iss/aud/sub 校验结果 |
| 是否支持所需 actor 表达 | 官方版本说明与实际 token;不从 client_id 猜 act |
| scope 能否扩大 | 请求未授权 scope 的反例与拒绝策略 |
| 委托撤销后如何阻止执行 | 短 token 生命周期之外的在线校验与反例 |
| 外部身份源或跨 realm | 不支持就明确排除,不用预览功能伪装稳定能力 |
Keycloak 当前文档的标准 Token Exchange V2 主要支持同 realm 的内部令牌交换;scope 和 audience 参数行为需要单独验证,不能假设 exchange 天然只缩权。本文没有验证所安装版本,也不声称其支持任意 actor_token 流程。Keycloak Token Exchange
若采用自有 actor 审计字段,必须来自已认证客户端和服务端注册映射,不能信任请求体的 actor_id。审计字段也不能冒充授权服务器签发的标准 claim。
5. 凭证代理与 MCP 边界
凭证代理保存加密的提供方凭证引用,对运行器只暴露业务动作接口。密钥与密文分离管理;日志、异常、链路追踪统一脱敏;撤销委托时阻止新凭证获取。已有下游 token 的失效窗口必须明确,不能承诺删除数据库记录就瞬间撤回所有 token。
Auth0 Token Vault 是集中处理第三方令牌的产品例子,可参考其职责划分,但本项目不依赖购买该产品。Auth0 Token Vault
如果加入 MCP:验证发给本 MCP 服务的访问令牌;下游调用另行获取适当凭证。MCP 安全指南明确禁止接受非本服务受众的 token 后直接透传下游。HTTP 传输鉴权与本地进程信任边界也应分别说明。MCP 安全实践
6. 审批不是一个 approved 布尔值
审批记录绑定:tenant_id、subject_id、grant_id/version、task_id、tool_id、目标资源、规范化参数摘要、业务资源版本、有效期、审批人。
执行前重新验证上述约束。标题、目标项目、收件人等关键参数改变必须重新审批。摘要规范化规则由服务端固定,拒绝重复键、歧义数字和未知字段,不对任意原始 JSON 随便做哈希。
撤权与执行之间的竞争
“先检查权限,再发请求”仍有时间差。第一版定义可检验语义:在工具服务最终授权检查前已提交的撤权必须阻止操作;已经提交成功的操作不承诺自动回滚。对于自有工单服务,在事务内比较 grant_version/资源版本并写入幂等操作记录。跨外部服务无法同事务时,记录剩余竞争窗口,对高风险操作采用下游支持的条件请求或再次人工确认。
7. 数据模型与接口草案
| 表 | 关键字段与约束 |
|---|---|
| agent_registration | client_id、允许工具、状态;由管理员注册 |
| delegated_grant | tenant_id、subject_id、动作与资源约束、expires_at、status、version |
| agent_task | grant_id、actor_ref、状态、截止时间、trace_id |
| action_approval | task_id、参数摘要、资源版本、grant_version、expires_at、审批人 |
| tool_operation | tenant_id、task_id、operation_key、request_hash、状态、外部结果标识;幂等键唯一 |
| security_audit | 主体、执行者、目标、策略版本、decision/reason、trace_id;不存 token |
建议接口:POST /delegations、POST /delegations/{id}/revoke、POST /agent-tasks、POST /approvals/{id}/confirm、POST /tool-executions、GET /operations/{id}。每个接口都校验调用方身份及对象归属;审批不能由执行 Agent 自己完成。
任务状态建议:PENDING → RUNNING → WAITING_APPROVAL → RUNNING → SUCCEEDED;失败、撤销、超时为独立终态。外部写入超时先进入 UNKNOWN 操作状态,不直接当失败重试。
幂等与不确定结果
同一业务动作重试复用 operation_key,相同 key 不同参数拒绝。数据库唯一约束处理并发,不能只依靠短期 Redis 锁。下游支持幂等时传递对应键;不支持时通过业务唯一标识查询和对账,无法确认就转人工,不声称端到端 exactly-once。
8. 待实现验收用例
以下是测试计划,未执行,不代表通过。
| 编号 | 输入或故障 | 预期 |
|---|---|---|
| B01 | 替换为其他租户文档 ID | 拒绝,无数据内容返回 |
| B02 | 运行器伪造 subject/actor | 忽略不可信字段或拒绝;审计使用认证身份 |
| B03 | 用知识服务 token 调工单服务 | audience 不符拒绝 |
| B04 | 申请委托外的 scope 或工具 | 网关与凭证策略拒绝,不扩大授权 |
| B05 | 审批后改工单项目或正文 | 摘要不匹配,重新审批 |
| B06 | 审批后撤权,再执行 | 最终授权点拒绝并记录原因 |
| B07 | 并发提交同一操作 | 最多创建一个业务工单,返回关联结果 |
| B08 | 下游成功但响应丢失 | 查询或对账确认,不盲目重复创建 |
| B09 | 文档包含越权工具指令 | 即使模型采纳,网关仍拒绝越权动作 |
| B10 | 查询日志、错误响应、模型请求记录 | 不出现真实 token、密钥或完整敏感文档 |
| B11 | 审批过期、委托过期、任务取消 | 写操作不执行 |
| B12 | 策略存储不可用或服务身份无效 | 写操作拒绝,错误可诊断且不泄密 |
9. 如何证明有工程深度
交付证据:脱敏链路追踪、鉴权反例、审批参数变化用例、数据库幂等约束、响应丢失对账日志、兼容性实验结果。固定策略和工具桩先测授权,再单独接模型测试候选动作质量,不能用模型答得对证明鉴权正确。
测量时分别记录网关自身耗时和包含模型/下游的端到端耗时,报告样本量、并发、环境、P50/P95、拒绝原因分布及错误率。当前所有结果均待测,不填写 QPS、可用性或“越权率降低 100%”。