localhost 上的 Webhook:无需公网端点即可测试验证回调
一个公开问题询问在 localhost 上开发时如何接收 webhook。托管服务商无法访问 127.0.0.1,因此在开发期间回调可能永远不会到达。我们不代表提问者,也不声称修复任何平台。在身份入驻场景中,相邻的决策很具体:当一个回调无法到达时,你的应用在等待期间应该怎么做?本文仅使用经过检查的本地合成示例给出一种答案。持久化一个带截止时间的待处理会话,将合成回调直接注入处理程序,并让缺失的回调在本地过期。缺失的回调绝不能变成批准。
curl https://gridzen.ai/console/api/quickstart/trial \
-H 'Content-Type: application/json' \
-d '{"task": "identity_onboarding", "scenario": "success"}'问题与你的决策
在 localhost 上,无法到达的回调看起来和响应缓慢的服务商一样:会话一直停留在 pending。危险的捷径是为了继续开发而手动批准用户,或把超时当作成功。你面前的决策其实更窄:是在本地、与网络投递分开地测试状态转换,还是必须先有一个真实的隧道沙盒,才能信任自己的逻辑?该示例支持第一种做法。它无需公网 URL、无需凭据、也不发起网络调用,就能检验你的状态处理。它不测试真实投递、签名或服务商重试。
示例实际实现了什么
Identity 类把会话和事件存储在 SQLite 中。create() 要求标识符以 fixture- 开头,timeout 取值在 1 到 3600 秒之间。它保存 pending 状态,并将 deadline 设为 now 加上 timeout。它返回指向 example.invalid 的 hosted_link,且 link_executable 为 false。event() 只接受 mode 为 synthetic_fixture、source 为 fixture_callback 的事件,其他 mode 或 source 会抛出 PRODUCTION_SIGNATURE_VERIFIER_NOT_IMPLEMENTED。事件 ID 也必须以 fixture- 开头。deadline 过后,recover() 会把处于 pending、review 或 unknown 的会话标记为 expired,并返回 provider_polled 为 false。它只在本地使会话过期,从不查询服务商。
假设性示例场景
假设一位开发者在笔记本上运行入驻流程。在 now=0 时以 timeout 60 创建会话,因此 deadline 为 60。任何回调都无法到达 localhost。开发者没有等待网络,而是注入一个合成事件 fixture-approved,状态为 Approved,policy 为 true。读取结果为 status approved、permission_granted true、grant_count 1、policy_version 1、allow_action true、live_permission_changed false。再次发送同一事件,返回的记录完全相同,grant_count 仍为 1。之后的 Declined 事件返回 status declined、permission_granted false,grant_count 仍为 1。在另一次运行中没有回调到达,在 now=61 时调用 recover。结果为 status expired、permission_granted false、grant_count 0、next review_or_authorized_provider_refresh、provider_polled false。
失败处理
针对未知会话、或 tenant 或 subject 不匹配的事件,会抛出 BINDING_MISMATCH。读取不存在的会话会抛出 SESSION_NOT_FOUND。无法识别的状态会把会话置为 unknown,绝不会变成 approved。截止时间之后到达的事件会得到 expired。针对已终结会话的事件不会重新打开会话;唯一的例外是对 approved 会话的 Declined 更正。你的应用应把上述每种情况都视为需要审核的理由,而不是最终会授予访问权限的重试。即使是已授予的结果,也只是本地示例记录:live_permission_changed 始终为 false。
建议的应用设计与示例行为
以上内容都是示例中已实现的行为。以下是建议的设计,需要你自行构建并验证。第一,仅为沙盒流量开放开发路由,或使用你有权使用的隧道。第二,加入针对具体服务商的签名验证。第三,截止时间到达时,执行有界且经授权的状态核对,而不是仅仅让会话过期。最后,用你自己的规则决定业务权限。示例中的 decide() 和 revise_policy() 方法演示了显式、带版本的批准,但合成权限不是真实的业务权限。可下载示例包含电话检查的四个分支以及身份流程,它与匿名的三场景 HTTP 试用不是同一回事。
验收清单
运行指南中列出的重启测试和超时测试。使用同一个 SQLite 数据库重启,确认待处理状态得以保留。确认重复事件后 grant_count 仍为 1。确认在截止时间之后调用 recover 返回 expired,且 provider_polled 为 false。确认非示例来源的事件会被拒绝。确认没有任何代码路径会把缺失的回调变成 approved。在使用任何真实沙盒之前,记录尚未证明的内容:签名验证、真实投递与重试、状态核对,以及真实用户权限。然后再决定保存的沙盒申请是否适合你的任务。
运行已检查的模拟示例
下载并解压 https://gridzen.ai/downloads/verification-delivery.zip,进入 verification_delivery,用 Python 3.10+ 运行。此本地示例不联网;独立身份实验请使用新的数据库。
python3 delivery.py identity --db /tmp/gridzen-article-fixture.sqlite来源与范围
https://gridzen.ai/guides/missing-verification-webhook/ https://gridzen.ai/guides/current-capabilities/ 依据已检查的来源快照与本地模拟;建议的业务规则属于设计建议,不代表已证明的生产行为。内容使用 AI 辅助写作,并经过独立审稿。
下载不等于运行成功;本地示例与在线沙盒分别测试。