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),仅供参考

相关新闻

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

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

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

2026/10/13 2:39:33 阅读更多 →
Natron 节点详解:G‘MIC Dithering 抖动滤镜的参数配置与实战应用

Natron 节点详解:G‘MIC Dithering 抖动滤镜的参数配置与实战应用

音视频视频处理图形学桌面应用 【免费下载链接】Natron Open-source video compositing software. Node-graph based. Similar in functionalities to Adobe After Effects and Nuke by The Foundry. 项目地址: https://gitcode.com/gh_mirrors/na/Natron 点击查看 …

2026/10/13 2:38:33 阅读更多 →
Natron G‘MIC Oldschool 8bits 节点参数详解与自动文档生成机制

Natron G‘MIC Oldschool 8bits 节点参数详解与自动文档生成机制

音视频视频处理图形学桌面应用 【免费下载链接】Natron Open-source video compositing software. Node-graph based. Similar in functionalities to Adobe After Effects and Nuke by The Foundry. 项目地址: https://gitcode.com/gh_mirrors/na/Natron 点击查看 …

2026/10/13 2:38:33 阅读更多 →

最新新闻

PS5通用调校指南:从HDR发灰、下载慢到手柄断连的排查与优化

PS5通用调校指南:从HDR发灰、下载慢到手柄断连的排查与优化

最近一位朋友新入手了PS5,连着问了我好几个问题:电视开HDR之后画面发灰,下载一个游戏等了一夜还没好,手柄玩到一半断连,重连又要重新匹配。我一边远程指导一边发现,这些疑难杂症其实跟“哪一台PS5”没什么关…

2026/10/13 3:19:47 阅读更多 →
接口自动化测试实战:Excel用例管理+unittest+xlrd+xlsxwriter

接口自动化测试实战:Excel用例管理+unittest+xlrd+xlsxwriter

/* 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 3:19:47 阅读更多 →
AnyPS5实战:基于官方链路的PS5游戏串流全攻略

AnyPS5实战:基于官方链路的PS5游戏串流全攻略

如果你家里的 PS5 只能老老实实待在客厅电视下面,那这台机器一大半的潜力其实都没被用上。AnyPS5 是我这段时间集中折腾的一个项目,思路特别直接:把 PS5 的画面和操作,通过游戏串流的方式,送到你手边任何一块屏幕上——…

2026/10/13 3:19:47 阅读更多 →
PMI参数的解读与应用分析

PMI参数的解读与应用分析

PMI是宏观经济的重要指标,这里尝试对PMI参数进行解读和分析。 1 定义与特征 1.1 定义 采购经理指数(PMI)通过对企业采购经理的月度问卷调查结果统计汇总、编制而成的指数, 涵盖企业采购、生产、流通等各个环节,包括制造业和非制造业领域&…

2026/10/13 3:19:47 阅读更多 →
Simulink风光储并网系统建模与协调控制策略详解

Simulink风光储并网系统建模与协调控制策略详解

1. 项目概述与整体系统方案选择风电和光伏是当前电力系统中发展最快的两类清洁能源,但两者的出力特性完全不同——风电随风速波动,光伏则受辐照度和温度制约,两者叠加后仍然存在天然间歇性。储能系统的加入就是用来弥补这种波动,把…

2026/10/13 3:19:47 阅读更多 →
小白程序员必备:收藏!从零开始掌握 Codex 大模型核心技术

小白程序员必备:收藏!从零开始掌握 Codex 大模型核心技术

本文深入解析 Codex 大模型的六层架构,涵盖模型、Runtime、Context、Tool、Sandbox 和 Environment 的功能与关系。通过分析 Agent Loop 的工作原理,揭示 Token 的计量方式以及 Context Window 与 Memory 的关联。文章还探讨了长任务中出现的“忘记”现象…

2026/10/13 3:18:47 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/12 18:11:17 阅读更多 →