Terminus 中基于 Web5 的 JWT 签名与验证:`cli/pkg/web5/jwt` 包实战指南

发布时间:2026/10/13 2:39:50

Terminus 中基于 Web5 的 JWT 签名与验证:`cli/pkg/web5/jwt` 包实战指南 云原生后端运维【免费下载链接】TerminusOpen-Source Personal Cloud OS for Always-On Agents项目地址https://gitcode.com/gh_mirrors/terminus2/Terminus点击查看免费下载导读在 Terminus 的 CLI 代码库中cli/pkg/web5是承载 DID去中心化标识符与 Web5 密码学能力的核心模块而jwt子包则在其上封装了面向 DID 的 JWT 签发与校验 API。本文以 cli/pkg/web5/jwt/README.md 为骨架结合 jwt.go、jws.go、bearerdid.go 等源码与测试用例完整讲解如何用 Go 为 DID 签发 JWT、如何校验 JWT以及Claims序列化、Purpose/Type选项、过期校验等底层实现细节。读完本文你可以直接在 Terminus 的 CLI 工程中复现完整的“创建 DID → 签发 JWT → 校验 JWT”链路也可以据此理解 Terminus 中基于 DID 的身份签名机制。说明文中所有路径均为当前仓库内的相对路径引用代码以仓库实际内容为准。背景web5包在 Terminus CLI 中的定位在深入jwt之前先理解它所在的模块。cli/pkg/web5是一个完整移植自 Web5 理念的 Go 实现目录结构如下cli/pkg/web5/ ├── crypto/ # 密钥管理与数字签名算法ecdsa / eddsa ├── dids/ # DID 解析、DID Core 数据模型、BearerDID ├── jwk/ # JSON Web Key 编解码 ├── jws/ # JSON Web Signature紧凑格式 JWS ├── jwt/ # 本文主角面向 DID 的 JWT ├── vc/ # 可验证凭证VC / vc-jwt └── pexv2/ # Presentation Exchange v2jwt包本身只包含两个文件与 README 中 Directory Structure 一节完全一致jwt ├── jwt.go # Claims / Decoded / Sign / Verify / Decode └── jwt_test.go # 签名、验证、编解码与畸形输入测试在仓库中jwt包并非孤立存在它被上游的vc包如 vcjwt.go 中调用jwt.Decode与jwt.Decoded.Verify以及 CLI 的 wizard 模块如 user_store.go 中调用jwt.Sign(claims, bearerDID, jwt.Type(JWT))实际使用因此本文讲解的 API 是经过真实调用链验证的。快速开始为 DID 签发一个 JWTREADME 中 Signing 一节的示例代码可直接运行其完整形态如下package main import ( fmt github.com/beclab/Olares/cli/pkg/web5/didjwk github.com/beclab/Olares/cli/pkg/web5/jwt ) func main() { // 1. 创建一个新的 BearerDIDdid:jwk默认 Ed25519 did, err : didjwk.Create() if err ! nil { panic(err) } // 2. 构造 ClaimsIssuer 填入 DID URI私有声明放入 Misc claims : jwt.Claims{ Issuer: did.URI, Misc: map[string]interface{}{c_nonce: abcd123}, } // 3. 签名得到紧凑格式 JWT signedJWT, err : jwt.Sign(claims, did) if err ! nil { panic(err) } fmt.Printf(compact JWT: %s\n, signedJWT) }需要注意两点示例中的didjwk.Create()实际对应仓库中的 didkey/didkey.goREADME 引用的导入路径是历史包名didjwk。Create()默认使用LocalKeyManager并以 Ed25519 生成密钥创建出的BearerDID同时包含 DID 字符串、KeyManager 与 DID Document。claims.Issuer会被jwt.Sign强制覆盖为did.URI。源码中明确写着// iss is required to be equal to the DIDs URI; claims.Issuer did.URI。也就是说签发时无需也无法手工指定其他 issuer这是 DID 语义的一部分——JWT 的签发者必须就是持有该 DID 的主体。测试用例 TestSign_IssuerOverridden 验证了这一点即使传入一个与did.URI不同的 Issuer解码后得到的 Issuer 仍等于did.URI。签发流程在源码中的实际路径jwt.Sign的实现位于 jwt.go其内部流程是解析可选的SignOpt选项Purpose与Type详见下文将claims.Issuer覆盖为did.URIjson.Marshal(claims)得到 payload委托给jws.Sign(payload, did, jwsOpts...)。而jws.Signjws.go进一步完成通过did.GetSigner(o.selector)从 DID Document 中选取一个 verification method 及其私钥用dsa.GetJWA根据公钥类型推导 JWA 算法名Ed25519 对应EdDSAsecp256k1 对应ES256K将kid设为did.Document.GetAbsoluteResourceID(verificationMethod.ID)即${did}#${verificationMethodID}形式的 DID URL以base64url(header) . base64url(payload)为待签数据计算签名最终拼出三段式紧凑 JWT。因此最终产物的 Header 大致为{alg:EdDSA,kid:did:jwk:...#0,typ:}kid携带完整 DID URL这正是验证方得以解析出公钥的关键见下文 Verifying 流程。用Type选项设置typ头README 提到“specifying a specific category of key ... can be done in the same way shown withjws.Sign”。jwt.Sign支持两个选项其中Type(t string)用于设置 JWT 头部的typ字段signedJWT, err : jwt.Sign(claims, did, jwt.Type(JWT))Terminus CLI 的 user_store.go 正是这样调用jwt.Sign(claims, bearerDID, jwt.Type(JWT))的。typ: JWT的意义在于让接收方一眼识别这是一个 JWT 而非普通 JWSvc包在校验 vc-jwt 时也会检查Header.TYP JWT见 vcjwt.go。用Purpose选项选择签名密钥Purpose(p string)用于指定使用 DID Document 中哪个验证关系的密钥来签名例如signedJWT, err : jwt.Sign(claims, did, jwt.Purpose(authentication))不传Purpose时默认使用assertionMethod断言方法。可选的目的值定义在 didcore/document.go 中Purpose 常量值语义PurposeAssertionassertionMethod用于签发断言、可验证凭证默认PurposeAuthenticationauthentication用于登录、挑战-响应等认证场景PurposeCapabilityDelegationcapabilityDelegation用于委托密码学能力PurposeCapabilityInvocationcapabilityInvocation用于调用密码学能力如更新 DID DocumentPurposeKeyAgreementkeyAgreement用于生成加密通信的密钥材料SelectVerificationMethoddocument.go会优先取对应目的列表中第一个 verification methoddid:key创建的 DID Document 将其唯一密钥同时登记到assertionMethod、authentication、capabilityDelegation、capabilityInvocation四种关系中见 didkey.go所以这几种 Purpose 都可以直接使用。校验 JWTVerify与Decoded.VerifyREADME 的 Verifying 示例package main import ( fmt github.com/beclab/Olares/cli/pkg/web5/dids github.com/beclab/Olares/cli/pkg/web5/jwt ) func main() { someJWT : SOME_JWT decoded, err : jwt.Verify(someJWT) if err ! nil { panic(err) } fmt.Printf(verified: %v\n, decoded) }注意 README 中ok, err : jwt.Verify(signedJWT)的写法与仓库实际签名略有出入——当前实现jwt.Verify(jwt string) (Decoded, error)直接返回解码结果与错误校验成功与否通过err nil判断而非布尔返回值。校验的三重检查jwt.Verifyjwt.go先调用Decode解析三段结构再调用Decoded.Verify()。Decoded.Verifyjwt.go按顺序执行过期检查若Claims.Expiration ! 0且time.Now().Unix() Expiration返回JWT has expired签名完整性检查将 JWT 组装为jws.Decoded并调用decodedJWS.Verify()失败返回JWT signature verification failed签发者一致性检查要求Claims.Issuer非空且Header.KID以Claims.Issuer为前缀否则返回JWT issuer does not match the did url provided as KID。其中第 2 步的 JWS 级校验jws.go是核心校验 Header 必须包含alg与kid用dids.Resolve(kid)解析出 DID Document用kid即 DID URL通过SelectVerificationMethod选出对应公钥调用dsa.Verify对parts[0] . parts[1]做签名验证。源码注释还提示了一个值得注意的优化点签发者一致性检查应尽早于网络型 DID 解析执行因为 DID 解析可能触发网络调用见 jwt.go 的 TODO 注释。这属于仓库作者留下的实现约束说明并非当前已实现的行为。错误与Decode的容错Decodejwt.go负责把三段base64url解码为Decoded其容错策略值得注意段数不为 3 →malformed JWT. Expected 3 parts, got NHeader 解码失败、Claims 解码/反序列化失败、Signature 解码失败均返回带malformed JWT前缀的错误用did.Parse(header.KID)解析签名者 DID失败同样报malformed JWT。对应的测试用例覆盖了空串、坏 Header、坏 Signature、kid不是合法 DID 等场景见 jwt_test.go可作为异常处理的参考行为。Decode本身不校验签名、也不校验过期适合仅需解析内容的场景Verify才是完整的校验入口。Claims注册声明与私有声明的扁平化处理Claims结构体jwt.go实现了 RFC 7519 定义的 7 个注册声明字段JSON 键含义RFC 7519Issueriss签发者Subjectsub主体Audienceaud目标受众Expirationexp过期时间Unix 秒NotBeforenbf生效时间Unix 秒IssuedAtiat签发时间Unix 秒JTIjtiJWT 唯一 IDExpiration与NotBefore均为 Unix 时间戳int64这与 JWS 的time时间戳语义一致过期判断由Decoded.Verify依据exp执行。Claims还包含一个特殊字段Misc map[string]any用于承载任意私有声明。README 示例中的c_nonce就通过Misc传入。为保证输出 JSON 是“注册声明 私有声明平铺在顶层”的标准形态Claims自定义了MarshalJSON与UnmarshalJSONjwt.go序列化先以cpyClaims 的拷贝类型避免无限递归序列化注册字段再把Misc中的键值逐一合并进顶层 map反序列化先把原始 JSON 展开为 map凡是iss/sub/aud/exp/nbf/iat/jti之外的键全部归入Misc注册字段再反序列化到cpy。TestClaims_MarshalJSON 与 TestClaims_UnmarshalJSON 验证了Misc中的键值在 JSON 往返中既不丢失、也不会与注册字段冲突。这意味着你可以放心地把自定义字段nonce、业务上下文等放进Misc最终 JWT 的 claims 部分会形如{iss:did:jwk:...,c_nonce:abcd123}谁在使用它vc-jwt 与 CLI 的实际调用为确认这套 API 的实战地位仓库中有两处真实调用vc 包vcjwt.go 用jwt.Decode(vcJWT)解码可验证凭证 JWT随后把iss、jti、sub、exp、nbf等注册声明“反填”进 VC 数据模型对应 W3C VC 数据模型中的 JWT 编码/解码约定最后用jwt.Decoded.Verify()做完整性校验。jwt.Decode的测试用例也使用了真实的 vc-jwt 样例见 jwt_test.go。wizard 模块user_store.go 的SignJWS用jwt.Sign(claims, bearerDID, jwt.Type(JWT))为 DID 用户签名请求载荷并把时间戳写入私有声明。这证明了jwt包不仅存在于 web5 内部还直接支撑着 CLI 的用户认证流程。常见问题与使用注意README 中ok, err : jwt.Verify(...)与当前 API 不一致仓库当前版本Verify返回(Decoded, error)请以源码 jwt.go 为准校验结果以err是否为nil判断。didjwk导入路径已迁移README 与历史文档中的cli/pkg/web5/didjwk在当前仓库中对应 cli/pkg/web5/dids/didkey创建 DID 请使用didkey.Create()。iss强制覆盖jwt.Sign会忽略你手工设置的Issuer这符合“JWT 签发者即 DID 持有者”的语义如需校验签发者一致性Decoded.Verify会检查kid前缀是否匹配iss。Decode与Verify的区别只解析不校验用Decode需要过期与签名双重校验用Verify。网络依赖JWS 级签名校验需要解析 DIDdids.Resolve。对于did:jwk/did:key这类静态 DID解析不依赖网络但设计上该路径是统一的解析入口README 与源码均提示部分 DID 方法如did:dht、did:web的解析器在仓库中仍为占位实现见 resolver.go实际使用时需确认对应 DID 方法的 resolver 已注册。目录结构与设计取舍jwt ├── jwt.go # Claims、Decoded、Sign、Verify、Decode、Marshal/UnmarshalJSON └── jwt_test.go # 覆盖签名、验证、iss 覆盖、claims 编解码、畸形输入README 的 Rationale 一节只写了一句“same asjws”对应的 jws/README.md 给出的设计理由是作者希望获得jws.Sign/jws.Verify这样简洁的 API。落实到代码上jwt与jws的分层是清晰的jwt负责 claims 语义注册声明、私有声明、issuer 约束、过期校验jws负责密码学与紧凑格式jwt.Sign内部委托jws.Signjwt.Decoded.Verify内部委托jws.Decoded.Verify职责单一、便于复用。这种“JWT 建立在 JWS 之上”的结构与 RFC 7519 / RFC 7515 的规范关系一一对应也是阅读与扩展此包时最值得抓住的主线。赞分享云原生后端运维【免费下载链接】TerminusOpen-Source Personal Cloud OS for Always-On Agents项目地址https://gitcode.com/gh_mirrors/terminus2/Terminus点击查看免费下载相关推荐Terminus Web5 Crypto 密码学包实战secp256k1 与 ed25519 的密钥生成、签名与验证Terminus Web5 Crypto 密码学包实战secp256k1 与 ed25519 的密钥生成、签名与验证 Terminus 的 cli/pkg/w云原生后端运维java-jwt 实战指南基于 RFC 7519 的 JWT 创建、签名与验证java jwt 实战指南基于 RFC 7519 的 JWT 创建、签名与验证 java jwt 是 Auth0 出品的 Java 语言 JSON Web T后端认证鉴权OpenCloud 中的 JWT 实战golang-jwt/jwt/v5 签名、验证与安全实践OpenCloud 中的 JWT 实战golang jwt/jwt/v5 签名、验证与安全实践 导读 JSON Web TokenJWT是当前身份认证与授后端微服务存储认证鉴权上一篇三步永久保存微信聊天记录你的数字记忆守护者下一篇Citra模拟器终极优化指南15分钟解决所有运行问题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/13 2:39:50

六款科研绘图AI的维普过检能力评分实测

论文返修意见里躺着一条刺眼的批注:"图3坐标轴单位缺失,图7图例与正文描述不符,请全面整改后重新提交。"实验室同门赶在截稿前把图表交给导师,结果被一句"这图能看出你做了三个月实验?"堵了回来。…

2026/10/13 2:39:50

JDK8 HashMap扩容机制深度解析:尾插法与高低位链表拆分

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 2:39:50

Go电商系统开发实战:订单、库存与幂等性设计要点

把“goshop 电商项目01”这个代号放在标题里时,我其实是想给自己做一份项目存档。这套项目不是网上常见的商品管理 demo,而是一套按真实小商户需求整理的电商系统雏形:前台能浏览商品、加购物车、下单,后台能管理商品、库存和订单…

2026/10/13 3:54:55

UE5视差材质原理与实操:POM节点、参数调优与避坑指南

简介:这套UE5视差材质资源包面向虚幻引擎开发者和视觉设计师,系统展示基于高度图的视差贴图技术,用于低成本营造物体表面深度感,提升场景真实度,可广泛应用于游戏开发、建筑可视化与电影制作。压缩包共478个文件&#…

2026/10/13 3:54:55

mfc140.dll丢失怎么修复?官方免费方法+深度排查思路

“由于找不到mfc140.dll,无法继续执行代码。重新安装程序可能会修复此问题。”如果你最近被这个弹窗卡住过,那多半是某个软件或游戏客户端突然打不开了。每次遇到这种弹窗,第一反应都是先上网搜一下“mfc140.dll丢失怎么解决”,结…

2026/10/13 3:54:55

软件配置管理实战:从版本控制到变更治理的完整解析

软件配置管理(SCM)这个东西,刚入行的开发可能觉得它就是“用Git管代码”,干了两三年以后,会发现事情远没有这么简单。我在带团队和做技术管理的这些年里,见过太多次因为配置管理没做好而引发的线上事故、团…

2026/10/13 3:54:55

Linux磁盘管理全攻略:分区、挂载、LVM、配额与排障实践

做运维这些年,我越来越发现一个事实:很多看似诡异的问题,最后都能在磁盘管理上找到病灶。要么是分区规划不合理导致空间浪费,要么是挂载配置写错开机直接进不了系统,要么是日志把根分区撑爆才发现当初没做配额。磁盘管…

2026/10/13 3:49:55

进程通信全解析:从管道到Socket的选型与实践

写进程通信这块内容,我心里一直有个念头:教科书把管道、消息队列、共享内存、信号量、Socket一个个平铺开来,讲完定义讲API,讲完API讲例子,但真到自己写多进程程序时,最常遇到的困惑是“我到底该用哪个”。…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介:这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师,聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案,解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件,约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型,最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支,让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图,十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑