动态身份验证
动态身份验证
您的 API 可能需要动态身份验证,其中需要为每个请求生成或刷新凭据,例如签名短期 JWT 或轮换令牌。TypeScript SDK 通过自定义 fetcher 中间件支持这种模式。
自定义 fetcher 中间件
在 TypeScript SDK 中实现动态身份验证的推荐方式是使用自定义 fetcher。这充当所有请求的中间件,允许您在单个位置注入身份验证逻辑,而无需重写单个方法。
工作原理
当您在生成器配置中启用 allowCustomFetcher 时,生成的 SDK 在客户端选项中接受 fetcher 参数。此 fetcher 包装所有 HTTP 请求,为您提供身份验证逻辑的单个注入点。
示例:短期 JWT 签名
以下是如何通过令牌记忆化实现 JWT 签名:
通过 packageJson 添加运行时依赖
使用 packageJson 配置选项添加 jsonwebtoken 依赖,以便它合并到生成的 package.json 中:
generators.yml
查看 TypeScript 配置页面 了解所有可用的 packageJson 选项。
创建包装器客户端
扩展生成的客户端以使用自定义 fetcher:
src/wrapper/PlantStoreClient.ts
这种模式使用 ConstructorParameters 从生成的客户端推断确切的选项类型,确保与所有客户端选项(headers、timeoutInSeconds、maxRetries 等)的兼容性,而无需硬编码它们。这使包装器在生成器添加新选项时保持向前兼容。
其他身份验证模式
这种相同的模式适用于其他动态身份验证场景:
- OAuth 令牌刷新:在每个请求之前自动刷新过期的访问令牌
- HMAC(基于哈希的消息身份验证代码)签名:基于请求内容使用 HMAC 签名对请求进行签名
- 轮换 API 密钥:基于速率限制在多个 API 密钥之间切换
- 基于时间的令牌:生成包含时间戳或随机数的令牌
重要考虑事项
自定义 fetcher 要求
- 生成器配置:必须在您的
generators.yml中启用allowCustomFetcher选项,以便fetcher参数在BaseClientOptions中可用 - 导入路径:从
../core/fetcher(或生成的 SDK 中的适当路径)导入默认 fetcher,以使用您的自定义逻辑包装它 - 保留所有参数:在包装默认 fetcher 时,确保传递所有参数以保持与 SDK 内部行为的兼容性
安全考虑事项
- 仅服务器端:永远不要在浏览器环境中暴露私钥。使用私钥进行 JWT 签名应该只在服务器端代码(Node.js、Deno、Bun)中进行
- 安全密钥存储:永远不要硬编码私钥;使用环境变量或安全密钥管理系统
- 避免双重身份验证:如果您的 API 在 Fern 定义中已经使用了 bearer token 身份验证,请小心不要覆盖现有的
Authorization头部。考虑使用不同的头部名称或有条件地设置头部
性能和并发
- 令牌记忆化:缓存令牌以避免在每个请求上重新生成它们。上面的示例缓存令牌并在过期前 2 秒刷新它们
- 线程安全:所示的记忆化模式在 JavaScript 的单线程事件循环中对并发请求是安全的,但在其他环境中要注意竞态条件
- 宽限期:在令牌过期前稍早刷新令牌(例如,提前 2 秒)以避免令牌在请求处理期间过期的边缘情况
头部合并
- 保留现有头部:在注入身份验证头部时,始终展开现有头部以避免覆盖 SDK 或用户设置的头部
- 头部优先级:头部按顺序合并:SDK 默认值 → 客户端选项 → 请求选项 → 自定义 fetcher。您的自定义 fetcher 最后运行,可以覆盖先前的头部
时间同步
- 时钟漂移:注意客户端和服务器之间潜在的时钟漂移。考虑为令牌过期检查添加容差
- 时间戳精度:对
iat和exp声明使用 Unix 时间戳(自纪元以来的秒数)以符合 JWT 标准
最佳实践
- 适当缓存令牌:在安全性(较短的令牌生命周期)和性能(较少频繁的重新生成)之间取得平衡
- 优雅处理错误:为身份验证失败和令牌刷新错误实现重试逻辑
- 彻底测试:确保您的包装器处理所有边缘情况,包括并发请求、令牌过期和网络故障
- 监控令牌使用:记录令牌生成和刷新事件以帮助调试生产中的身份验证问题
另请参阅
- 添加自定义代码 - TypeScript 特定的自定义指南
- TypeScript 配置 - 配置选项的完整列表