You need to enable JavaScript to run this app. 基于HMACSHA256的JWT签名校验接近正常但无法通过的问题排查
优惠活动
大模型
产品
解决方案
定价
更多

基于HMACSHA256的JWT签名校验接近正常但无法通过的问题排查

签名校验失败的根因定位

编码标准不匹配

从你贴的日志对比可以直接看到两个签名的具体差异:

JWT自带的示例签名:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
程序计算得到的签名:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV/adQssw5c=
这些差异刚好是标准Base64与JWT要求的Base64URL编码的固定区别:

  • 标准Base64用/表示的编码段位,JWT规范要求替换为_
  • 标准Base64末尾会追加=做长度对齐填充,JWT要求完全移除所有填充字符

你当前代码使用Java默认的Base64.getEncoder()做HMAC结果编码,这是标准Base64实现,输出的字符串自然无法和JWT中Base64URL格式的签名匹配。

测试代码的逻辑错误

你在补充测试逻辑里的这段写法存在低级漏洞:

byte[] header64 = Base64.getEncoder().encode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes());
byte[] payload64 = Base64.getEncoder().encode("{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022}".getBytes());
// 错误实现
final byte[] calcHmacSha256 = HMAC.calcHmacSha256("your-256-bit-secret".getBytes(), (header64+"."+payload64).getBytes());

Java中直接将byte数组和字符串做+拼接时,会自动调用byte数组的默认toString()方法,输出类似[B@1a2b3c的内存地址标识,根本不是Base64编码后的实际文本内容。相当于你拿去计算HMAC的待签字符串完全错误,算出的哈希结果从根源上就不对。

修正操作指引
  • HMAC计算完成后,替换编码实现:将原来的Base64.getEncoder().encodeToString(calcHmacSha256)改为Base64.getUrlEncoder().withoutPadding().encodeToString(calcHmacSha256),这个内置编码器会自动适配JWT的Base64URL要求,不需要手动替换字符、删除填充符
  • 构造测试JWT时,先将Base64编码后的字节数组转换为对应字符串,再拼接待签串:先把header、payload的Base64字节转成可读的Base64文本,再拼成headerStr + "." + payloadStr的格式,取这个字符串的字节做HMAC计算,不要直接拼接byte数组。

内容的提问来源于stack exchange,提问作者Capitano Giovarco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.15 15:15:01