Agent 代表用户,但不能拥有用户的全部权限
当 Agent 代表用户行动时,用户权限应是上限,不是自动下发给 Agent 的完整权限包。
很多企业在接入 Agent 时会选择一条看起来最自然的路径:
用户登录
→ Agent 获取用户 Token
→ Agent 使用该 Token 调用 MCP Server
→ MCP Server 再调用 CRM、ERP 或其他业务系统
这个方案保留了用户身份,也能复用现有权限,看上去比共享服务账号安全得多。
但它仍然漏掉了一个关键问题:
用户此刻允许这个 Agent,为了这项任务,在多长时间内,对哪些对象,执行多少次什么动作?
“用户能做”只回答了第一层。它没有回答 Agent 能否自动做、能做几次、能否批量做、是否允许重试,以及任务结束后权限何时失效。
因此,企业 Agent 的有效权限不应该等于用户权限,而应该是多个权限集合的交集:
有效权限
= 用户原生权限
∩ Agent 身份策略
∩ 当前任务委托
∩ Tool / Action 约束
∩ 运行时风险与审批策略
∩ 业务系统当前状态
任何一层拒绝,执行都应该停止。
人的权限是为人机交互设计的
传统企业权限通常默认操作主体是人。
人通过页面逐项浏览,输入参数,查看确认框,再点击提交。一次操作之间存在天然摩擦:
- 页面切换需要时间;
- 批量操作通常需要额外入口;
- 异常提示会中断流程;
- 高风险操作可能要求再次确认;
- 人会根据结果改变下一步计划。
Agent 则不同。它可以在几秒内循环调用同一工具,自动扩展对象范围,在超时后重试,并把一个模糊目标拆成几十个写操作。
于是,同一个“允许修改订单”的权限,交给人和交给 Agent,实际风险并不相同。
人:打开订单 → 修改字段 → 确认一次
Agent:搜索订单 → 批量修改 → 超时重试 → 继续扩展范围
ACL 只看到每次调用是否合法,却未必知道这是一项什么任务、累计影响了多少对象、是否已经超过用户最初的意图。
这就是为什么用户权限只能作为 Agent 的权限上限。
先区分委托和冒充
OAuth 2.0 Token Exchange 的 RFC 8693 明确区分了两种语义。
冒充:Agent 在上下文中就是用户
在 Impersonation 模式下,A 冒充 B。对接收方而言,A 在授权上下文中与 B 不可区分。
这种方式兼容性很好,因为下游系统只需要继续识别用户。但它会削弱追责能力:日志可能只显示用户做了某件事,无法稳定证明实际执行者是哪个 Agent、哪个版本和哪次任务。
委托:用户是 Subject,Agent 是 Actor
在 Delegation 模式下,用户仍是权利主体,Agent 保留独立身份,并被明确标记为代表用户行动。
RFC 8693 的 act Claim 可以描述当前 Actor;嵌套的 act 还能记录此前的委托链。
例如:
{
"sub": "user:zhangsan",
"act": {
"sub": "agent:procurement-copilot-v7"
},
"aud": "purchase-api",
"scope": "purchase-order.submit"
}
这个 Token 表达的不是“Agent 就是张三”,而是:
当前权利主体:张三
当前执行主体:采购 Agent v7
目标资源服务:采购 API
授权范围:提交采购单
对于 Agent 场景,委托通常比冒充更接近事实。
OBO 保留用户权限,但不会自动生成任务边界
Microsoft Entra 的 On-Behalf-Of(OBO)流程是企业常见实现。
官方文档描述的流程是:中间层 API 收到面向自己的用户 Token,然后向身份平台申请一个面向下游 API 的新 Token。下游 Token 使用 Delegated Scope,而不是把中间层收到的 Token 原样转发。
OBO 解决了几个重要问题:
- 用户身份和权限沿调用链传播;
- 中间层需要用自己的凭据参与换 Token;
- 新 Token 绑定下游 Audience;
- 下游只获得用户已经同意和管理员允许的 Delegated Scope;
- 条件访问需要 Step-up 时,可以返回 Claims Challenge。
但 OBO 并不自动知道业务任务。
假设用户有 invoice.approve 权限,OBO 可以帮助 Agent 获得面向财务 API 的委托 Token。它通常不会仅凭协议自动知道:
只允许批准这 3 张发票
每张金额不超过 5 万元
总金额不超过 10 万元
仅限今天 15:00 前
供应商不能出现在制裁名单
同一发票只能提交一次
这些是任务委托和业务动作约束,不是通用 OAuth Scope 能单独完整表达的内容。
所以更准确的关系是:
OBO / Token Exchange
→ 建立身份和 Audience 正确的委托链
Delegation Grant / Action Contract
→ 进一步收窄对象、动作、时间、次数和风险
两者缺一不可。
不要把用户 Token 原样穿透整条链
为了保留用户身份,有些 MCP 实现会把客户端 Token 原样传给下游 API。
这不是委托,而是 Token Passthrough。
MCP 2026-07-28 Security Best Practices 将其明确列为反模式:MCP Server 不应接受并转发未明确签发给自己的 Token,必须验证 Audience。否则会破坏 OAuth 的资源边界,造成 confused deputy、控制绕过和审计归属混乱。
正确调用链应是:
用户 / Agent Host
└─ Token A,aud = MCP Server
MCP Server 验证 Token A
└─ 使用 OBO 或 Token Exchange 获取 Token B
下游业务 API
└─ Token B,aud = 业务 API
Token A 与 Token B 可以保留同一用户 Subject,但不应是同一个不变的 Bearer Token。
每跨越一个资源服务器边界,都应该重新绑定 Audience,并尽可能进一步缩小 Scope。
一个完整委托应该包含什么
只记录 user_id 和 agent_id 远远不够。
企业可以把一次 Agent 委托定义为可验证的 Delegation Grant:
{
"grant_id": "dg_20260822_001",
"subject": "user:zhangsan",
"actor": "agent:procurement-copilot",
"actor_version": "7.3.1",
"purpose": "为华东项目提交本周采购申请",
"actions": ["purchase_order.create", "purchase_order.submit"],
"resources": {
"project_ids": ["project-east-2026"],
"supplier_ids": ["supplier-a", "supplier-b"]
},
"limits": {
"max_order_amount": 50000,
"max_total_amount": 100000,
"max_operations": 5
},
"valid_until": "2026-08-22T15:00:00+08:00",
"approval_policy": "amount_over_30000_requires_manager",
"delegation_depth": 0
}
这个 Grant 至少回答:
- 谁授权;
- 哪个 Agent 和版本在执行;
- 为了什么任务;
- 允许哪些具名动作;
- 可以影响哪些对象;
- 金额、数量和累计上限;
- 生效与失效时间;
- 是否允许继续转委托;
- 哪些情况必须升级审批。
它不一定全部放进 Access Token。较复杂的约束可以保存在策略服务中,Token 只携带 grant_id、Audience、基础 Scope 和 Actor,再由 PDP 在执行时读取对应策略版本。
用户有权限,不等于用户已经表达意图
授权系统还要区分长期权限和即时意图。
张三可能长期拥有取消订单的权限,但这不表示他每次说“处理一下异常订单”时,都授权 Agent 自动取消所有异常订单。
一次可靠的执行应保留至少三类证据:
Entitlement
张三在业务系统中拥有 cancel_order 权限
Delegation
张三将订单 A、B 的取消动作委托给 Agent X
Intent / Confirmation
张三确认了取消原因、对象范围和预期影响
长期 Entitlement 是必要条件,不是即时同意。
对于低风险读取,用户发起对话本身可能足以构成任务意图;对于付款、删除、合同签署或批量变更,则需要结构化确认或审批。
权限收窄不能只靠 Scope
Scope 很重要,但通常粒度较粗。
invoice.read
invoice.approve
customer.update
这些 Scope 适合表达能力类别,却很难独立表示实例范围、金额上限、次数和状态前置条件。
因此,企业 Agent 的权限收窄至少应有四层:
第一层:身份与 Scope
确认 Subject、Actor、Audience 和允许的能力类别。
第二层:资源关系
确认用户、Agent 和目标对象之间的组织、项目、区域或负责关系。
第三层:Action Predicate
确认对象当前状态、金额、数量、字段、版本和业务前置条件。
第四层:运行时预算
确认本次任务累计调用次数、累计金额、批量大小、速率和剩余有效期。
只有四层都通过,Tool 才可以真正执行。
MCP 的 Scope Minimization 指南也强调渐进式最小权限:先获取低风险基础 Scope,在首次触发高风险操作时再进行精确的 Scope Challenge,而不是一开始申请 admin:* 或 full-access。
三种模式不要混在一起
不是所有 Agent 都在代表某个在线用户。
模式一:交互式用户委托
用户在线
→ 明确发起任务
→ Agent 代表用户执行
有效权限受用户权限和即时委托共同约束。这是 OBO 最典型的场景。
模式二:离线任务委托
用户或审批人预先创建任务
→ Agent 稍后异步执行
这里不能依赖一个长期保存的用户会话 Token。应使用有明确用途、有效期和撤销机制的任务 Grant,再在运行时换取短期 Token。
模式三:Agent 自主职责
企业直接授予 Agent 某项持续职责
→ Agent 以自身身份运行
例如每日检查证书到期、归档低风险日志或监控库存阈值。此时 Agent 使用自己的权限,不是在代表某位用户。
这也是标题必须加边界的地方:
“用户权限是 Agent 权限上限”只适用于代表该用户执行的委托模式。对于自主 Agent,应以 Agent 自身职责、Sponsor、策略和服务权限为边界,不能伪造一个用户作为 Subject。
为什么共享服务账号不是解决方案
有些企业为了避免 OBO 和委托建模,直接让所有 Agent 使用一个高权限服务账号。
这样做短期集成最快,长期代价很高:
- 无法区分哪个 Agent 在执行;
- 无法证明代表哪个用户或业务任务;
- 权限只能按所有用例的并集配置;
- 一个凭据泄露会影响全部工具;
- 单个 Agent 无法独立撤权;
- 版本升级后很难区分新旧行为;
- 源系统日志只看到共享账号;
- Sponsor 和生命周期无人负责。
如果下游只支持服务账号,至少也应由中间 Action Service 校验用户、Agent、Delegation Grant 和动作约束,并把这些证据写入不可抵赖的审计记录。共享账号只能是兼容性实现,不能成为授权模型。
一个退款案例
用户对客服系统拥有最高 5000 元退款权限。
如果 Agent 直接继承完整权限,它理论上可以:
对任意订单退款
单笔最高 5000 元
不断重复调用
在整个登录会话期间持续有效
更合理的委托是:
Subject:客服 A
Actor:售后 Agent v12
Action:refund_order
Resource:订单 20260822001
Max amount:300 元
Count:1
Reason:物流超时补偿
TTL:10 分钟
Require readback:是
执行点再检查:
- 客服 A 当前仍有退款权限;
- Agent v12 没有被禁用;
- Delegation Grant 未过期且未撤销;
- 订单属于客服 A 可处理范围;
- 当前状态允许退款;
- 退款金额未超本次 Grant;
- 幂等键未被使用;
- 累计预算仍充足;
- 下游支付系统最终接受;
- 读回结果与预期一致。
这样,“客服可以退款”才被收窄成“这个 Agent 可以执行这一次退款”。
审计不能只写“用户调用了工具”
Agent 动作审计应保留完整链条:
subject_user
actor_agent_id
actor_version
agent_instance
mcp_client_id
mcp_server_id
downstream_client_id
delegation_grant_id
tool_name + tool_version
action_name + policy_version
input_digest
resource_ids
approval / confirmation evidence
attempt_number + idempotency_key
result + downstream_receipt
post-action readback
如果下游只记录用户,就无法区分人直接操作和 Agent 代办。
如果只记录 Agent,又无法知道它在代表谁、基于哪次委托。
Subject 与 Actor 必须同时存在,才能进行问责、撤权和事故调查。
常见反对意见
“Agent 就是用户的数字分身”
数字分身是一种产品隐喻,不应成为安全模型。
用户会收到恶意内容、犯输入错误,也会拥有超出当前任务的长期权限。Agent 还会循环、并发、重试和自主规划。身份上的代表关系不能消除执行方式的差异。
“我们已经使用 OBO,所以权限足够安全”
OBO 解决用户身份传递、Audience 和 Delegated Scope,不自动解决具体对象、金额、次数、TTL、审批、幂等和任务意图。
它是委托基础设施,不是完整任务授权系统。
“每个 Agent 都有独立身份,运维成本太高”
这是真的,但共享身份只是把成本转移到了审计、撤权和事故处置阶段。
Microsoft Entra Agent ID 已经把“区分 Agent 操作、按 Agent 配置适量权限、阻止访问关键角色、支持大量动态创建和销毁”列为 Agent Identity 要解决的问题。这说明 Agent 生命周期正在成为 IAM 的正式对象,而不是日志中的一段 User-Agent 字符串。
“低风险只读场景不值得建立完整 Grant”
也成立。
公开数据查询、低敏感搜索或无副作用的个人辅助,可以使用短期 OBO Token 加基础 Scope,不必为每次读取创建复杂审批。
关键不是所有动作都采用最高治理强度,而是按风险分层,不能让低风险便利模式自动扩展到付款、删除和批量写入。
建议的落地顺序
第一步:停止共享高权限 Token
至少区分用户、Agent、MCP Server 和下游 API 的身份与 Audience。
第二步:为 Agent 建立可追踪身份
记录稳定的 Agent ID、版本、Owner/Sponsor、部署环境和状态。详细生命周期治理将在本系列下一篇展开。
第三步:把高风险 Tool 改造成具名 Action
避免 update_record、execute_sql 和任意 URL 调用,改为参数和副作用明确的业务动作。
第四步:引入 Delegation Grant
先覆盖高风险写操作,只实现最关键字段:Subject、Actor、Action、Resource、TTL、次数/金额和审批要求。
第五步:在执行点计算交集
PDP 的 Allow 只是前置条件;Action Service 与源系统仍保留最终 Deny。
第六步:测试撤权和过期
验证用户撤权、Agent 禁用、Grant 过期、策略升级和任务取消后,已有会话与缓存能在目标时限内失效。
结论
当 Agent 代表用户行动时,用户权限回答的是:
这名用户最多可以做什么?
企业还必须回答:
这次任务允许哪个 Agent 做什么?
对哪些对象?
在多长时间内?
做几次?
累计影响多大?
由谁审批?
如何撤销和审计?
因此,正确模型不是复制用户权限,而是保留 Subject 和 Actor,再持续衰减权限:
用户长期权限
→ 当前 Agent 身份可用范围
→ 本次任务委托
→ 具名业务动作
→ 实例、时间、次数和预算约束
→ 运行时审批与源系统最终校验
Agent 可以代表用户,但不应该因为“代表”二字,就自动拥有用户全部权限。
真正安全的委托,不是把钥匙交出去,而是签发一张随任务失效、范围可验证、每次使用都能追责的通行证。
参考资料
- OAuth 2.0 Token Exchange(RFC 8693)
- Microsoft identity platform:OAuth 2.0 On-Behalf-Of flow
- Microsoft Entra Agent ID:What are agent identities
- MCP 2026-07-28:Security Best Practices
- OAuth 2.0 Security Best Current Practice(RFC 9700)
- JWT Profile for OAuth 2.0 Access Tokens(RFC 9068)
发布摘要
用户已经拥有业务系统权限,Agent 是否可以直接继承?本文从 OAuth 委托与冒充、Subject/Actor、OBO、MCP Token Passthrough 和任务级 Delegation Grant 出发,说明用户权限为什么只能作为 Agent 的权限上限,以及如何用对象、时间、次数、金额、审批和运行时预算把长期权限收窄为一次可追责的业务动作。
标签
AI Agent MCP OAuth 2.0 权限系统 IAM Delegation On-Behalf-Of Agent Identity 企业架构 零信任