系统设计面试:如何设计请求绑定的委托权限验证层?
题目与适用场景
请设计一个委托权限验证层:代理、工作负载或批处理任务代表用户或组织调用会花费资金、消耗计量资源、披露受监管数据或修改生产状态的 HTTP API。系统需要在执行受保护请求前证明请求方拥有有界权限。题目参考 IETF HTTPAPI 的 2026 年 Internet-Draft;该文档仍是 work in progress,不能视为最终 RFC,也不等于支付协议。
面试官考察点
- 能否区分身份认证、委托授权、请求完整性和结算流程。
- 能否设计 401 挑战、403 拒绝、nonce、过期时间和请求绑定。
- 能否处理重放、跨租户混用、代理转发、密钥轮换和审计。
- 能否在高风险动作前设置预算、策略和故障安全边界。
回答前需要澄清的问题
- 受保护动作是导出数据、写生产资源、调用下游,还是消费预算?
- 委托方、签发方、执行请求方和验证方分别由谁运营?
- 权限需要绑定 HTTP 方法、目标 URI、请求摘要,还是只绑定资源范围?
- 允许离线验证吗?nonce 状态可用性和时钟偏差如何处理?
- 失败时应拒绝请求、进入人工审批,还是降级为只读?
30 秒回答框架
把问题拆成四层:已有身份凭据证明“是谁”,委托证明说明“代表谁、能做什么、上限是多少”,请求绑定证明“只能用于哪一次请求”,验证策略决定“现在是否允许”。没有合格委托证明时返回 401 challenge;证明存在但权限不足时返回 403。证明应包含签发者、请求方、主体、过期时间、nonce、目标方法与 URI、摘要和预算边界。验证成功后再执行动作,所有失败路径都默认拒绝并保留审计。
分步骤深入解答
1. 定义角色与信任边界
主体是用户、组织或服务;委托请求方是代理、设备、任务或工作负载;签发方代表主体签发证明;验证方位于受保护资源或网关。OAuth Token Exchange 等系统可以负责取得证明,但验证层只负责挑战和呈现,不重复定义同意流程或账户绑定。
2. 设计挑战与响应
没有可接受证明时,验证方返回 401、WWW-Authenticate: Delegation 和 Cache-Control: no-store。证明语法有效但超过本地策略时返回 403。错误体可用 Problem Details,但不能让解释字段放宽挑战约束。
HTTP/1.1 401 Unauthorized
Cache-Control: no-store
WWW-Authenticate: Delegation realm="api.example",
version=1, profile="budget", nonce="n-123", max-age=300挑战中的 nonce、profile 和过期窗口应由验证方控制,避免跨请求复制。
3. 绑定到将要执行的请求
证明至少绑定 HTTP 方法、可信 origin、目标 URI、请求内容摘要和有效期。代理重写 Host 或路径时,验证方只使用受信任的网关配置重建 origin,不能采信未经验证的 X-Forwarded-*。方法大小写、查询参数顺序和百分号编码必须定义规范化规则。
{
"principal": "org-42",
"requester": "job-7",
"method": "POST",
"origin": "https://api.example",
"target_hash": "sha-256:...",
"nonce": "n-123",
"expires": "2026-08-04T05:00:00Z",
"limits": {"USD": 250}
}4. 验证顺序与故障安全
先解析版本和格式,再验证签名、签发者信任、nonce 未重放、时间窗口、请求绑定和本地预算。任何依赖不可用、CBOR 非确定性、签名失败或 nonce 状态丢失都拒绝请求,不能在验证异常时自动放行。身份凭据与委托证明分层验证,不能把一个有效证明当成另一个 API key 的授权。
5. 防止重放和跨租户混用
nonce 存储需要短 TTL、原子消费和租户隔离;请求摘要与目标 origin 防止把同一证明复制到另一条 API。验证方应拒绝已使用 nonce,限制时钟偏差,并对预检与最终请求使用一致的绑定字段。高风险动作可以要求一次性证明和人工审批。
6. 预算与策略执行
预算只是一个权限 profile,不等于支付或结算。策略可以限制金额、服务单位、数据范围、环境和下游调用次数。扣减应在动作提交的同一事务边界内完成,或者使用可补偿的预留记录,避免并发请求共同超过上限。
7. 密钥、审计和可运维性
签发者发布可轮换的公钥与版本;验证方缓存但必须支持撤销和紧急密钥切换。审计记录主体、请求方、目标、策略结果、证明 ID 和拒绝原因,绝不记录完整 token、私钥或敏感数据。指标包括 401/403 比例、nonce 重放、验证延迟、策略拒绝、预算超限、密钥轮换失败和人工审批耗时。
高质量示范回答
我会把系统拆成身份、委托、请求绑定和策略四层。OAuth 或其他签发系统证明主体关系,委托证明携带主体、请求方、权限 profile、过期时间和预算;验证方再把证明绑定到即将执行的 HTTP 方法、可信 origin、目标 URI、请求摘要与 nonce。
没有证明时返回 401 和 WWW-Authenticate: Delegation,带 no-store;证明有效但权限不足返回 403。验证顺序是格式、签名和签发者信任、nonce 未使用、时间窗口、请求绑定、租户策略和预算。任何签名失败、依赖不可用或 nonce 状态丢失都默认拒绝。证明本身不定义支付,不替代 HTTP Message Signatures,也不等于 OAuth 的签发或用户同意流程。
预算扣减必须与动作提交处于同一事务或可补偿边界;nonce 要原子消费并隔离租户。公钥支持轮换和紧急撤销,日志只保留证明 ID、主体、目标和结果。验收关注重放、跨租户复制、代理改写、并发超支和密钥轮换,最终目标是在高影响动作发生前证明“谁代表谁、能对哪条请求做什么”。
常见错误
- 把委托证明当成通用身份认证、OAuth 签发流程或支付协议。
- 只签发一个长期 token,不绑定方法、URI、摘要、nonce 和过期时间。
- 在签名验证依赖不可用时放行请求,造成故障不安全。
- 忽略代理重写和不可信
X-Forwarded-*导致的目标混淆。 - 记录完整凭据或把预算扣减放在动作之后,留下重放和超支窗口。
追问及应对
为什么需要 401 和 403 两种响应?
401 表示缺少、无效或不完整的委托证明,客户端可能通过 challenge 获取新证明;403 表示证明被理解但权限、预算或本地策略不足,重试同一证明没有意义。
nonce 服务短暂不可用时怎么办?
默认拒绝高风险请求,并保留 no-store 的可诊断错误。只有经过明确风险评估的低风险只读动作才可采用受限降级,不能把缓存的旧 nonce 当作一次性状态。
如何兼容 OAuth?
OAuth Token Exchange 或 GNAP 可以负责取得委托材料;验证层仍独立检查 request-bound proof。身份 token 与委托 proof 分别验证,避免把委托范围误当作身份 token 的全部权限。
这是不是支付协议?
不是。预算 profile 可表达金额或服务单位上限,但结算、支付轨道和 HTTP 402 的语义在系统外部定义,验证层只决定受保护动作是否满足委托策略。