SuperAPI AI 工具集

fastify-better-auth-bridge

编程与开发

查看项目

更新于 10-15 08:17

技能介绍

Fastify Better Auth Bridge 用于把 Better Auth 的会话解析接入 Fastify 5,方式是通过 onRequest 钩子完成桥接。当 Better Auth 已经存在、但 Fastify 缺少对应的框架桥接时,可以使用这个技能。

适用与不适用

适用场景:Better Auth 已存在,需要为 Fastify 5 补上框架桥接。

不应加载该技能的情形:问题出在回调 URL 配置、可信来源(trusted origins)或提供方引导顺序;问题出在 IDCS 组映射或 org_members 供应规则;目标是围绕 Better Auth 另建一套并行会话系统。

必须避免的做法

不要在只需要转发 cookie 头的情况下另建并行会话层——症状(没有会话)与修复(转发 cookie)之间隔着两层,很容易误诊。

不要在桥接的 onRequest 钩子里执行 RBAC 策略——桥接负责解析身份,路由守卫负责执行访问控制;把两者混在一起会让双方都难以测试。

不要在 Fastify 5 中共享可变的数组装饰器默认值——原型上的数组会被所有请求共享;应使用基于 Symbol 的每请求 getter/setter。

不要跳过 Web Request 桥接——auth.api.getSession() 需要原生 Web API Request,而不是 Fastify 请求对象;传入错误类型会静默地返回无会话。

不要假设在 Fastify 5 中 reply.send(undefined) 是安全的——它会抛出异常。

几个不明显的要点

为什么 cookie 转发会静默失败:缺少 cookie 头会让登录和会话解析在完全不同的位置失败——登录成功(在浏览器中设置了 cookie),但下一个请求没有会话。没有报错,会话只是 null。桥接与登录流程看起来互不相关。始终要确认你构建的 Web Request 中包含了 cookie。

为什么 Fastify 5 的装饰器数组会共享状态:fastify.decorateRequest('permissions', []) 中的 [] 是原型默认值,被所有请求共享。第一个请求修改它,第二个请求就会看到上一个请求的权限。应使用以 Symbol 为键的 getter/setter,为每个请求分配新数组。

为什么 IDCS 用户没有活动组织:IDCS 供应的用户是通过组同步创建的,而不是通过 Better Auth 的组织切换流程。他们的会话没有 activeOrganizationId。期望组织上下文的下游代码会静默收到 undefined。当 activeOrganizationId 缺失时,可通过查询 org_members 来修补。

所需的桥接形态

第 1 步:Web Request 桥接。由协议 + 主机名 + URL + 方法 + 完整传入头构建。头中必须包含 cookie——这是 auth.api.getSession() 能解析会话的唯一途径。

第 2 步:一次性装饰请求状态。统一为:request.user、request.session、request.permissions、request.apiKeyContext。对任何持有数组或可变对象的字段,使用基于 Symbol 的 getter/setter。

第 3 步:路径排除。仅对以下路径跳过会话解析:health、metrics、Better Auth 处理路由。匹配前先规范化查询字符串和尾部斜杠——规范化不一致会导致某些路由上出现认证遗漏。

第 4 步:解析会话,出错时以匿名身份继续。如果 auth.api.getSession() 抛出异常:记录日志,并以 request.user = null 继续。绝不要在桥接层拒绝请求——那是路由守卫的职责。

第 5 步:修补组织上下文。如果 request.session.activeOrganizationId 缺失,按用户 ID 查询 org_members 并在下游设置组织上下文。仅在组织上下文确实缺失时这样做——不要把它当作每个请求的默认回退。

诊断脚本

node scripts/check-fastify-auth-bridge.js /path/to/auth-plugin.ts

未提供参数时默认使用 apps/api/src/plugins/auth.ts

参数

$ARGUMENTS:可选,指向要检查的 Fastify 认证插件文件路径。为空 = 使用仓库默认路径(apps/api/src/plugins/auth.ts)。