拓冰建站拓冰建站
首页 / 资讯中心 / 正文

jose 通用 JWS 签名构建器 Signature 接口深度解析:General JSON Serialization 多签名实战指南

网络安全认证鉴权后端【免费下载链接】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 库中 Signature 接口src/jws/general/sign.ts展开它是在 General JSON Serialization 序列化下构建一个 JWS 携带多条独立签名的核心 API。读完本文你将掌握 Signature 接口全部五个方法setProtectedHeader、setUnprotectedHeader、addSignature、sign、done的签名与语义、它与父级 GeneralSign 的委托关系、底层校验逻辑头部互斥、crit/b64一致性并能直接写出可运行的多签名 JWS 生产代码。一、背景为什么需要 Signature 接口JWSJSON Web Signature除了常见的 Compact Serialization三段式紧凑字符串之外还定义了General JSON Serialization整个 JWS 是一个 JSON 对象其signatures数组成员各自携带独立的签名与头部。这种形态特别适合多方联合背书同一份 payload 需要 EC 密钥与 RSA 密钥或不同算法分别签名供不同类型的验签方校验兼容不同消费方签发方无法预知接收方支持哪种算法便一次性提供多种算法签名受保护与不受保护头部并存部分头部如kid只需完整性保护即可部分头部可放在未受保护的header成员中。jose 用 GeneralSign 类来构建这种多签名对象而Signature 接口正是 GeneralSign 为每一条待添加的签名返回的构建器句柄——每条签名都有自己独立的头部与密钥状态最后统一由sign()落盘。官方文档对它的定位是Used to build General JWS objects individual signatures用于构建 General JWS 对象的单条签名对应源码中的注释与实现src/jws/general/sign.ts。二、Signature 接口方法全景依据 Signature.md该接口共声明五个方法全部支持链式调用。逐一说明1.setProtectedHeader(protectedHeader): Signature参数protectedHeader类型为 JWSHeaderParameters即 JWS 受保护头部。语义为当前这条Signature 设置受保护头部。受保护头部的全部成员会参与签名输入的计算被 BASE64URL 编码后拼入protected成员因此受到完整性保护。返回值Signature便于继续链式调用。从源码可见该方法内部通过assertNotSet保证每个签名只能设置一次重复调用会抛出TypeError: setProtectedHeader can only be called oncesrc/jws/general/sign.ts测试见 test/jws/general.test.ts。2.setUnprotectedHeader(unprotectedHeader): Signature参数unprotectedHeader同为 JWSHeaderParameters。语义为当前这条 Signature 设置不受保护的头部。该头部作为未编码的 JSON 对象写入最终 JWS 的header成员不参与签名输入计算因此不具完整性保护详见 FlattenedJWSInput.md 对header成员的说明。.addSignature(secret) .setProtectedHeader({ bar: baz }) // 完整性保护 .setUnprotectedHeader({ alg: HS256 }) // 仅展示不参与签名输入同样只允许调用一次src/jws/general/sign.ts。关键约束源码级createSignature在 src/lib/jws_sign.ts 中强制两条规则——setProtectedHeader与setUnprotectedHeader至少调用一个否则抛JWSInvalideither setProtectedHeader or setUnprotectedHeader must be called before #sign()受保护与不受保护头部的成员名必须互斥disjoint否则抛JWSInvalidJWS Protected and JWS Unprotected Header Parameter names must be disjoint。3.addSignature(key, options?): Signature参数key为 KeyInput即CryptoKey | KeyObject | JWK | Uint8Array之一私钥或对称密钥/口令options?为可选的 SignOptions。语义它是在父级 GeneralSign 上再添加一条新签名的便捷转发方法shorthand。调用它会命中父实例的addSignature()并返回新签名对应的 Signature 构建器。源码实现一目了然src/jws/general/sign.tsaddSignature(...args: ParametersGeneralSign[addSignature]) { return this.#parent.addSignature(...args) }这意味着你可以在任一条签名构建的过程中岔开去追加新的签名链式写法非常自由见下文完整示例。4.sign(): PromiseGeneralJWS语义同样是转发方法调用父级 GeneralSign.sign()对已收集的所有签名统一执行签名计算返回Promise[GeneralJWS](https://link.gitcode.com/i/d198364201864eddad43317d248077a9)。它不接收任何参数——每条签名各自的密钥已在各自的addSignature中提供。sign(...args: ParametersGeneralSign[sign]) { return this.#parent.sign(...args) }5.done(): GeneralSign语义返回包裹当前签名的父级 GeneralSign 实例用于在链式调用的中途需要跳出回父级继续操作例如追加新签名后再回到原构建器的场景。done() { return this.#parent }三、完整实战示例EC 与 RSA 双签名官方文档给出的典型示例GeneralSign.md直观展示了上述方法的组合const jws await new jose.GeneralSign( new TextEncoder().encode(It’s a dangerous business, Frodo, going out your door.), ) .addSignature(ecPrivateKey) .setProtectedHeader({ alg: ES256 }) .addSignature(rsaPrivateKey) .setProtectedHeader({ alg: PS256 }) .sign() console.log(jws)先new jose.GeneralSign(payload)payload 必须是Uint8Array构造器签名GeneralSign.md第一条签名用 EC 私钥alg: ES256第二条用 RSA 私钥alg: PS256注意第二条addSignature是在第一条签名返回的 Signature 构建器上调用的——这正是addSignature转发语义的威力所在。输出形如{ payload: SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4, signatures: [ { protected: eyJhbGciOiJFUzI1NiJ9, signature: ... }, { protected: eyJhbGciOiJQUzI1NiJ9, signature: ... } ] }依据 GeneralJWS.md顶层对象由payload字符串与signatures若干去掉payload成员的 FlattenedJWS 输入组成。算法与密钥对应关系alg必须与密钥类型/长度匹配例如ES256需要 P-256 曲线 EC 私钥、PS256需要 RSA 私钥。jose 官方以 Algorithm Key Requirements 形式维护了各算法的密钥要求清单JWSHeaderParameters.md 中alg字段的说明。若密钥与算法不匹配sign()会在密钥准备阶段抛错对应 src/lib/jws_sign.ts 中prepareKey(entry, key, sign)的校验。四、底层实现IndividualSignature 与状态元组从源码结构看Signature接口的默认实现是IndividualSignature类src/jws/general/sign.ts可以推断其设计要点状态集中管理每条签名的状态被放进一个四元组SignatureState [protectedHeader, unprotectedHeader, key, crit]构造时初始化为[undefined, undefined, key, options?.crit]父引用私有字段#parent: GeneralSign保存父实例四个转发/返回方法addSignature、sign、done均围绕它实现一次性设置setProtectedHeader/setUnprotectedHeader都通过assertNotSet拒绝重复调用保护状态不被覆盖。父级GeneralSign维护#signatures: IndividualSignature[]数组sign()逐条调用createSignaturesrc/lib/jws_sign.ts核心流程为serializeProtectedHeader → 校验 protected/unprotected 至少一个且互斥 → 合并 joseHeader → validateSignatureHeadercrit/b64 校验 → signatureAlgorithm(alg) 解析算法 → signSignature 拼接签名输入并计算 → 组装 FlattenedJWSsignature / payload / protected / header五、签名级校验与多签名一致性约束GeneralSign.sign()src/jws/general/sign.ts在生成阶段还施加三条重要约束测试用例覆盖如下约束触发条件异常至少一条签名未调用addSignature直接sign()JWSInvalid: at least one signature must be addedpayload 类型payload 非Uint8ArrayTypeError: payload must be an instance of Uint8Arrayb64 模式一致不同签名对b64RFC 7797 非编码载荷的使用不一致JWSInvalid: inconsistent use of JWS Unencoded Payload (RFC7797)最后一条尤其关键同一个 General JWS 的所有签名必须统一使用或统一不使用b64: false因为多条签名共享同一个payload成员。测试 test/jws/general.test.ts 专门验证了混合 b64 模式会被拒绝而 test/jws/general.test.ts 验证了全部使用b64: false时payload返回空字符串原始载荷需要接收方另行提供。其余校验还包括JOSE 头部值必须是普通对象null、数组、Date、数字、布尔值等均被拒绝见 test/jws/general.test.ts、crit数组去重validateCritDuplicates、alg缺失或非法时报JWSInvalid: JWS alg (Algorithm) Header Parameter missing or invalidsrc/lib/jws_sign.ts。六、头部参数与 SignOptions 实战速查JWSHeaderParameters 常用成员受保护/不受保护头部都接受 JWSHeaderParameters除alg外的常用成员包括成员类型说明algstring签名算法必填kidstringKey ID便于验签方在 JWKS 中选钥critstring[]关键头部扩展名列表标记必须被理解并处理的头部b64booleanRFC 7797 扩展头部控制 payload 是否做 BASE64URL 编码typstring类型声明通常用于声明JWT等媒体类型ctystring内容类型jkustringJWK Set URL指向可公开获取的密钥集jwkobject内联公钥不允许携带私钥/对称密钥参数x5u/x5c/x5tstring/string[]/stringX.509 URL、证书链、SHA-1 指纹此外该接口允许任意自定义成员索引签名[propName: string]: unknown例如测试中使用的bar: baz。SignOptions.crit 详解SignOptions.md 中crit是唯一选项一个{ [name: string]: boolean }映射值为true表示该扩展头部必须被完整性保护即必须出现在受保护头部中false表示无关紧要。内置处理的是b64扩展头部其余注册头部并不享受内置特殊处理。文档同时给出重要警告该选项只做语法与完整性保护层面的检查不会替你处理该头部的业务语义——签名成功后调用方仍必须按协议 profile 自行校验其存在性并完成相应处理。七、常见陷阱与建议忘记设置头部setProtectedHeader与setUnprotectedHeader至少调用一个否则sign()直接抛JWSInvalid头部名冲突同一签名内受保护与不受保护头部不允许出现同名成员b64 模式必须全局一致多条签名要么全部b64: true默认要么全部b64: false配合crit: [b64]混用即报错重复设置同一头部同一条签名上setProtectedHeader/setUnprotectedHeader只能各调用一次payload 必须是Uint8Array字符串等类型会在sign()时被拒绝文本记得先用TextEncoder().encode()转换。结语Signature 接口是 jose 通用 JWS 签名能力的每签名构建器配合 GeneralSign 使用即可轻松产出多算法、多方背书的 General JSON Serialization JWS。建议进一步阅读src/jws/general/sign.ts接口与实现、src/lib/jws_sign.ts签名输入与头部校验、test/jws/general.test.ts边界与一致性测试以及配套的 JWSHeaderParameters、SignOptions 与 GeneralJWS 类型文档。赞分享网络安全认证鉴权后端【免费下载链接】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点击查看免费下载相关推荐KubeSphere 中的 Go JOSEgo-jose v2JWE / JWS / JWT 加密签名库深度解析KubeSphere 中的 Go JOSEgo jose v2JWE / JWS / JWT 加密签名库深度解析 本文以 KubeSphere 仓库中 v后端云原生容器编排微服务windows-services用 Rust 实现 Windows 服务的完整实战指南windows services用 Rust 实现 Windows 服务的完整实战指南 导读 windows services 是 windows rsRu网络安全认证鉴权后端Quartz 插件系统完全指南插件类型、内置插件清单与配置管理Quartz 插件系统完全指南插件类型、内置插件清单与配置管理 本文以 Quartzv5插件系统的官方索引文档为核心系统梳理插件生态的组成方式从内部插网络安全认证鉴权后端上一篇UE5-MCP如何用AI在3天内完成虚幻引擎5游戏开发工作下一篇零代码RPA自动化工具taskt3天掌握办公自动化的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门