
网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载jose 提供的customFetch是一个以unique symbol形式导出的特殊选项键将其传入 createRemoteJWKSet 的第二个参数后可以完全接管“远程 JSON Web Key SetJWKS的 HTTP 获取”这一环节从而启用高级 fetch 配置、HTTP 代理、网络错误重试、请求日志甚至测试桩mock等能力。读完本文你将掌握customFetch的精确签名、四种开箱即用的实战用法ky 重试与日志、undici 代理、undici 重试、undici 测试模拟以及它在 jose 源码内部真实的调用链与错误处理语义。customFetch 是什么一个键、一种类型、一套契约在 jose 中customFetch并不是一个函数而是一个unique symbol。它由 src/jwks/remote.ts 导出export const customFetch: unique symbol Symbol()之所以使用symbol而不是字符串属性名是为了避免与RemoteJWKSetOptions上的普通选项如timeoutDuration、headers发生键冲突。它作为RemoteJWKSetOptions的可选计算属性存在见 RemoteJWKSetOptions 接口interface RemoteJWKSetOptions { // ... [customFetch]?: FetchImplementation }与customFetch配套的FetchImplementation类型见 FetchImplementation 类型别名精确定义了你需要实现的函数形态type FetchImplementation ( /** 要发起请求的 URL */ url: string, /** 本应直接传给全局 fetch 的 options 参数 */ options: { headers: Headers // HTTP 请求头 method: GET // 请求方法固定为 GET redirect: manual // 重定向策略固定为 manual signal: AbortSignal // 用于超时/取消 }, ) PromiseResponse也就是说你提供的函数接收(url, options)两个参数返回一个PromiseResponse——这与原生fetch的调用约定完全一致因此任何符合该形态的 fetch 兼容实现如 ky、undici.fetch、Node 全局 fetch都可以无缝替换。它由 jose 主入口统一导出见 src/index.ts你可以直接import { customFetch, createRemoteJWKSet } from jose使用createRemoteJWKSet本身也同时支持从子路径jose/jwks/remote导入。为什么需要 customFetchcreateRemoteJWKSet默认使用全局fetch发起 JWKS 请求。但在真实生产环境中全局fetch往往不足以满足需求企业网络要求流量经过指定的 HTTP/HTTPS 代理弱网或间歇性故障环境下需要自动重试网络错误需要记录每次出站请求与响应以便排查问题或做审计单元测试中不希望真正发起网络请求而希望用 mock 拦截响应。customFetch正是为这些场景预留的“后门”把 fetch 的决策权完全交给你而 jose 只负责组装好url与options并消费返回的Response。实战一用 ky 实现自动重试与请求/响应日志ky 是 sindresorhus 开发的轻量级 fetch 封装内置指数退避重试默认重试 2 次与丰富的事件钩子。将customFetch指向 ky 后你既能获得重试能力又能借助hooks记录出站请求、重试事件和响应import ky from ky import { createRemoteJWKSet, customFetch } from jose // 前置条件按你的实际场景赋值 let url!: URL let logRequest!: (request: Request) void let logResponse!: (request: Request, response: Response) void let logRetry!: (request: Request, error: Error, retryCount: number) void const JWKS createRemoteJWKSet(url, { [customFetch]: (...args) ky(args[0], { ...args[1], // 透传 jose 组装的 headers/method/redirect/signal hooks: { beforeRequest: [ (request) { logRequest(request) }, ], beforeRetry: [ ({ request, error, retryCount }) { logRetry(request, error, retryCount) }, ], afterResponse: [ (request, _, response) { logResponse(request, response) }, ], }, }), })关键点在于...args[1]jose 会把headers、method: GET、redirect: manual、signal完整传入你只需原样展开给 ky即可保住 jose 内置的超时中止与请求头行为。beforeRequest、beforeRetry、afterResponse三个钩子分别覆盖“发请求前”“重试前”“响应后”三个时机足以支撑完整的可观测性需求。实战二用 undici 的 EnvHttpProxyAgent 自动探测并使用 HTTP 代理在 Node.js 服务端环境中许多部署要求所有外呼流量经由代理。undici 的EnvHttpProxyAgent会读取HTTP_PROXY/HTTPS_PROXY/NO_PROXY等环境变量并自动为请求选择代理配合customFetch即可让 JWKS 请求也走代理import * as undici from undici import { createRemoteJWKSet, customFetch } from jose let url!: URL // 自动从环境变量读取代理配置参见 undici 的 EnvHttpProxyAgent 文档 let envHttpProxyAgent new undici.EnvHttpProxyAgent() // ts-ignore const JWKS createRemoteJWKSet(url, { [customFetch]: (...args) { // ts-ignore return undici.fetch(args[0], { ...args[1], dispatcher: envHttpProxyAgent }) }, })dispatcher是 undici fetch 的扩展选项用于指定底层 Agent 实例...args[1]依然透传 jose 的标准选项。这段代码让 JWKS 获取自动适配企业代理环境无需手写任何代理解析逻辑。实战三用 undici 的 RetryAgent 自动重试网络错误默认全局 fetch 在遇到ECONNRESET、ECONNREFUSED这类瞬时网络错误时会直接失败导致 JWT 校验中断。undici 的RetryAgent可以针对特定错误码自动重试import * as undici from undici import { createRemoteJWKSet, customFetch } from jose let url!: URL let retryAgent new undici.RetryAgent(new undici.Agent(), { statusCodes: [], // 只重试网络错误不重试 HTTP 状态码 errorCodes: [ ECONNRESET, ECONNREFUSED, ENOTFOUND, ENETDOWN, ENETUNREACH, EHOSTDOWN, UND_ERR_SOCKET, ], }) // ts-ignore const JWKS createRemoteJWKSet(url, { [customFetch]: (...args) { // ts-ignore return undici.fetch(args[0], { ...args[1], dispatcher: retryAgent }) }, })这里将statusCodes置为空数组、仅针对errorCodes重试是一个经过刻意收敛的配置HTTP 层错误如 404、5xx仍交由 jose 处理并直接失败只有底层网络错误才触发重试避免对远端不稳定服务做无意义的过度重试。值得注意的是jose 源码中默认是不做任何网络错误重试的自定义RetryAgent正好弥补了这一环详见下文源码分析中的测试佐证。实战四用 undici 的 MockAgent 在测试中模拟 JWKS 响应在单元测试中你既不希望依赖真实网络也不想为 mock 重写整个解析链路。undici 的MockAgent配合customFetch可以拦截请求并返回预设的 JWKS 数据且能严格禁止真实网络连接import * as undici from undici import { createRemoteJWKSet, customFetch } from jose let url!: URL let mockAgent new undici.MockAgent() mockAgent.disableNetConnect() // 禁止任何真实网络请求 // ts-ignore const JWKS createRemoteJWKSet(url, { [customFetch]: (...args) { // ts-ignore return undici.fetch(args[0], { ...args[1], dispatcher: mockAgent }) }, }) // 随后按需对 mockAgent 注册拦截规则 // mockAgent.get(https://as.example.com).intercept({ path: /jwks }).reply(200, jwks)jose 自己的测试套件正是这么做的在 test/jwks/remote.test.ts 中测试代码创建MockAgent、disableNetConnect()然后把包装后的undiciFetch通过[customFetch]传入createRemoteJWKSet见 test/jwks/remote.test.ts从而在完全离线的环境下验证jwtVerify的完整流程。类型注意事项为什么要写 ts-expect-error官方文档对此有一个明确的已知坑Known caveat当你把customFetch的入参透传给 ky、undici.fetch 这类 fetch 兼容模块时极大概率会遇到类型不匹配——因为这些模块的签名几乎不可能与标准fetch完全一致例如 undici 的 options 比标准多出dispatcherky 的 options 又包含hooks等扩展字段。文档建议在透传处使用ts-expect-error明确豁免Expect Type-related issues when passing the inputs through to fetch-like modules, they hardly ever get their typings inline with actual fetch, you shouldts-expect-errorthem.这也是上面所有示例中反复出现// ts-ignore或// ts-expect-error注释的原因。在真实项目中更推荐把这些兼容函数抽成一个带宽松类型签名的工具函数把豁免注释集中在一处而不是散落在业务代码里。源码级原理customFetch 在内部如何被消费理解了用法之后再看 jose 内部如何使用customFetch能帮你更准确地预判行为。在 src/jwks/remote.ts 中fetchJwks是唯一调用你自定义实现的入口async function fetchJwks(url, headers, signal, fetchImpl fetch) { const response await fetchImpl(url, { method: GET, signal, redirect: manual, headers, }).catch((err) { if (err.name TimeoutError) { throw new JWKSTimeout() } throw err }) if (response.status ! 200) { throw new JOSEError(Expected 200 OK from the JSON Web Key Set HTTP response) } try { return await response.json() } catch { throw new JOSEError(Failed to parse the JSON Web Key Set HTTP response as JSON) } }由这段代码可以提炼出几个与customFetch直接相关的契约参数形态固定jose 始终以method: GET、redirect: manual、signal来自AbortSignal.timeout(timeoutDuration)和组装好的headers调用你的实现返回的Response会被response.json()消费HTTP 状态码语义只要响应状态不是200无论你的自定义实现做了什么重试、代理、mock最终都会抛出JOSEErrorExpected 200 OK from the JSON Web Key Set HTTP response。因此自定义实现不应在“非 200”上自行放行超时映射如果请求因AbortSignal.timeout中止而抛出名为TimeoutError的错误会被映射为JWKSTimeout错误码ERR_JWKS_TIMEOUT见 src/util/errors.tsJSON 解析失败即使你的实现正常返回响应若response.json()失败也会抛出JOSEErrorFailed to parse the JSON Web Key Set HTTP response as JSON。另外src/jwks/remote.ts 显示默认会注入两个请求头User-Agent: jose/v6.2.10浏览器环境为了规避不必要的 CORS 预检会省略以及accept: application/json, application/jwk-setjson。自定义实现透传...args[1]时这些头会被保留如果你完全丢弃传入的 options则需要自行补充。在调用策略层面createRemoteJWKSet采用“惰性 冷却窗口”模型src/jwks/remote.ts只有缓存过期或没有键匹配时才触发一次请求且在cooldownDuration默认 30 秒内成功获取后不再重复请求以防止滥用reload()方法则可绕过冷却窗口强制刷新。多个并发触发会被合并到同一个pendingFetchsrc/jwks/remote.ts其中对 Cloudflare Workers 这类无状态运行时有专门的pendingFetch重置处理src/jwks/remote.ts——这意味着即使你注入自定义 fetch这部分并发合并与冷却语义依然生效。与其它选项的协同customFetch不是孤立存在的选项它通常与 RemoteJWKSetOptions 中的其余配置配合使用选项默认值说明timeoutDuration5000 ms请求超时超时后中止并抛JWKSTimeout必须是非负整数cooldownDuration30000 ms成功获取后在此窗口内不再触发新请求防止滥用cacheMaxAge600000 ms10 分钟缓存 JWKS 的最大有效期超过后重新获取headers见上附加到请求的额外 HTTP 头[jwksCache]—云函数等无法常驻内存缓存场景下的可写缓存对象见 jwksCache 变量[customFetch]全局fetch自定义 fetch 实现本文主题例如你可以在使用customFetch的同时收紧timeoutDuration、放宽cooldownDuration并用headers携带认证信息——这些都由 jose 组装后原样传给你的实现。测试佐证customFetch 在 jose 测试套件中的实际覆盖jose 的官方测试 test/jwks/remote.test.ts 全面覆盖了customFetch相关行为可作为你实现自测的参考基线正常校验流通过[customFetch]注入包装后的 undici fetch配合MockAgent拦截https://as.example.com/jwks验证jwtVerify能成功校验签发的 JWTtest/jwks/remote.test.ts网络错误传播测试直接命中真实网络场景验证ENOTFOUND、ECONNREFUSED会被原样向上抛出并携带err.cause.codetest/jwks/remote.test.ts——这正是“用 RetryAgent 重试这类错误码”能生效的前提超时映射将timeoutDuration: 500与[customFetch]组合验证超时最终抛出errors.JWKSTimeouttest/jwks/remote.test.ts响应控制通过可控的 fetch 实现先挂起再逐一 resolve验证并发reload()的去重与新旧序列取舍test/jwks/remote.test.ts。这些测试从侧面印证了一个结论customFetch只是替换“发请求”这一步其上游的缓存、冷却、超时、并发合并与错误映射语义全部由 jose 自身保证不会因为换了 fetch 实现而丢失。小结customFetch是 jose 远程 JWKS 模块留出的一个高价值扩展点以unique symbol作为选项键、以FetchImplementation类型定义契约让你的 JWKS 获取从“全局 fetch 一步到位”升级为可代理、可重试、可观测、可 mock 的生产级网络栈。将其与 createRemoteJWKSet 的冷却窗口、缓存有效期、超时等内置策略组合使用即可在保持 jose 安全语义不变的前提下把远程 JWKS 的获取行为完全掌控在自己手中。更完整的模块视图可参考 jwks/remote 文档 及其中的 RemoteJWKSet 接口。赞分享网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载相关推荐jose 远程 JWKS 的 FetchImplementation 类型自定义 fetch 函数的签名契约、内部调用链与实战配置jose 远程 JWKS 的 FetchImplementation 类型自定义 fetch 函数的签名契约、内部调用链与实战配置 远程 JSON Web K网络安全认证鉴权后端AutoDev项目中自定义测试代理的上下文变量实现AutoDev项目中自定义测试代理的上下文变量实现 引言为什么需要上下文变量 在AI驱动的编程辅助工具中上下文理解是核心挑战。传统的代码生成工具往往缺乏对人工智能大模型AI Agent代码智能体开发工具工具调用后端前端抖音自动上传工具一键批量发布视频的终极指南抖音自动上传工具一键批量发布视频的终极指南 抖音自动上传工具是一款专为内容创作者打造的自动化视频发布神器能够帮你实现从视频采集到发布的完整自动化流程。这款开工作流自动化网页爬虫视频处理上一篇GHelper终极指南华硕笔记本性能优化神器轻量级替代Armoury Crate下一篇AWS CLI 实践指南使用 aws codecommit update-comment 更新 CodeCommit 提交评论创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考