审批生命周期与授权绑定
审批不是一个布尔值,而是对具体动作、资源、参数摘要、批准人、有效期和版本的授权。展示给用户的确认内容必须与最终执行内容一致;模型修改收件人、金额或文件后,旧审批立即失效。审批过期、撤回和资源变化都要有明确终态。
第一个可运行实验:摘要与期限绑定
保存为 approval.py,用 Python 3.12 运行。
python
import hashlib, json
def digest(action):
return hashlib.sha256(json.dumps(action, sort_keys=True).encode()).hexdigest()
def check(approval, action, now):
if approval['status'] != 'approved':
return 'not_approved'
if now >= approval['expires_at']:
return 'expired'
if approval['digest'] != digest(action):
return 'action_changed'
if approval['resource_version'] != action['resource_version']:
return 'resource_changed'
return 'allowed'
action = {'kind': 'send', 'to': 'a@example.com', 'resource_version': 3}
permit = {'status': 'approved', 'expires_at': 20, 'digest': digest(action), 'resource_version': 3}
assert check(permit, action, 10) == 'allowed'
assert check(permit, {**action, 'to': 'b@example.com'}, 10) == 'action_changed'
assert check(permit, action, 20) == 'expired'
print('approval lifecycle passed')批准人、展示文案和最终 payload 应保存同一摘要。高风险操作可以要求二次确认、双人审批或人工接管;低风险查询不需要伪造审批。审批记录要防重放,不能让客户端自行构造“已批准”字段。
变体实验
将资源版本从 3 改为 4,要求旧审批失效。再将审批状态改为 revoked,确认即使未过期也不能执行。
练习
- 设计审批撤回和超时后的状态迁移。
- 为付款、删除、发信分别定义确认摘要中的关键字段。
- 说明为什么审批 TTL 不能替代每次执行时的权限检查。