工具鉴权、审批绑定与幂等账本:练习答案
参考实现
追加:
python
import sqlite3, json, hashlib
c = sqlite3.connect(":memory:")
c.executescript("CREATE TABLE actions(tenant TEXT, key TEXT, digest TEXT, result TEXT, PRIMARY KEY(tenant,key)); CREATE TABLE drafts(id INTEGER PRIMARY KEY, body TEXT);")
def digest(payload):
return hashlib.sha256(json.dumps(payload, sort_keys=True).encode()).hexdigest()
def create_draft(tenant, key, payload, approval):
if tenant != "a" or set(payload) != {"body"} or not isinstance(payload["body"], str):
raise PermissionError("not allowed")
d = digest(payload)
if approval != (tenant, key, d): raise PermissionError("approval does not bind action")
with c:
row = c.execute("SELECT digest,result FROM actions WHERE tenant=? AND key=?", (tenant,key)).fetchone()
if row:
if row[0] != d: raise ValueError("key reused with changed payload")
return row[1]
cur = c.execute("INSERT INTO drafts(body) VALUES (?)", (payload["body"],))
result = str(cur.lastrowid)
c.execute("INSERT INTO actions VALUES (?,?,?,?)", (tenant,key,d,result))
return result
p = {"body":"hello"}; permit = ("a", "job-7", digest(p))
assert create_draft("a", "job-7", p, permit) == "1"
p2 = {"body":"bye"}
for approval, error in [(permit, PermissionError), (("a","job-7",digest(p2)), ValueError)]:
try: create_draft("a","job-7",p2,approval)
except error: pass
else: raise AssertionError("changed action accepted")
assert c.execute("SELECT count(*) FROM drafts").fetchone()[0] == 1
print("approval and idempotency bound")重新批准改变的是授权,不应改变原幂等键的业务身份;新动作要分配新键。
深化页面练习解答
工具授权
用户权限、服务身份和资源拥有者是不同维度;批量工具应逐项返回 allowed、denied 或 stale。长任务需要在领取、执行和提交前重新检查权限与资源版本。
审批生命周期
审批可以进入 approved、expired、revoked、action_changed 和 resource_changed。付款确认绑定金额、币种、收款方和资源版本;删除绑定资源与范围;发信绑定收件人、主题和正文摘要。TTL 不能替代实时权限检查。
远程幂等
outbox 至少维护 pending、sent、succeeded、failed 和 unknown。查询不可用时不能判断未执行;取消也不能证明远程副作用未发生,应查询、等待或人工核对。