service-jwt-trust-boundary

服务间 JWT 信任边界

认证服务把每一个请求都当成不可信的,直到它证明自己来自一个已知的调用方。一个 Fastify 插件在整个应用前面挂上一个 onRequest 钩子,于是信任校验发生在任何路由处理器之前——只有一个咽喉点,而不是每条路由各自判断。

两条进入的路。 请求可以在 Authorization 头里带一个服务令牌(Bearer 方案),或者——对那些从不持有共享密钥的调用方而言——带一个由签名密钥握手建立起来的会话。两者都不满足的,一律回一个干脆的 401。健康检查端点是有意的例外:它们在一张忽略清单上,无需令牌即可通过,而且这张清单可以追加额外的路由,从而有意地放开特定路由。

身份由验签成功的那把密钥决定,而不是令牌里的声明。 插件持有一份小小的可信调用方注册表,每个调用方都绑定它自己的签名密钥。它拿令牌逐一去试每把密钥;调用方的身份由哪一把密钥验签成功来决定,而令牌自己声称的"我是谁"字段在这个判断里从不被信任。这是承重的设计选择——它让调用方的身份是密码学绑定的,而不是自我声称的,于是令牌无法谎报自己的来源。有些调用方还被额外标记为足够可信,登录时可以跳过人机校验那一步,因为它专属的密钥本身就是可信的证明。

令牌是一个手写的、基于 HMAC-SHA256 的 JWT。 签名与验证直接建在 Node 的 crypto 原语上,而不是用某个 JWT 库。验证会重新计算 header 与 payload 上的签名,任何不匹配都拒绝,并且还要求 header 声明的算法与类型符合预期——所以令牌无法降级或替换自己的算法。过期(exp)与签发时间(iat)会对着当前时间校验,并留了一个很小的、有界的时钟偏移容差,于是机器之间几秒的漂移不会造成误拒,而真正过期或来自未来的令牌仍会被拒绝。

要吵,不要哑。 可信调用方注册表在启动时从配置里装配,每一把必需的密钥都是强制的——只要缺一把,服务就拒绝启动,而不是悄悄地跑着却无法认证那个调用方。配置出错是一次崩溃,而不是一个静默的洞。

这个边界不是什么。 它只回答"这个请求来自一个可信的服务吗?"它不提取用户身份——那是另一件事,由会话 cookie 承载、在别处处理。把两者分开,服务信任校验才能保持简单、只干一件事。

相关

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →

service-jwt-trust-boundary