使用JJWT生成JWT在jwt.io调试器验证失败求助
解决JJWT生成JWT在jwt.io验证失败的问题
先排查代码里的明显错误
- Token分割逻辑错误:TestHarness里的
token.split(token, '.')写法完全错误,应该改成token.split("\\.")(.是正则表达式特殊字符,需要转义),否则无法正确分割JWT的header、payload、signature三个部分。 - 时间戳单位错误:JWT标准中
iat和exp要求是秒级Unix时间戳,但你的代码用了current.getTime()返回的毫秒级时间戳(如1672761664338),这会导致jwt.io判定时间异常,直接验证失败。需要修正时间戳处理:// 修正getUnixTime方法,返回秒级时间戳 public static long getUnixTime() { return System.currentTimeMillis() / 1000; } // 测试代码里的timeNow也要改成秒级:1672761664L
核心问题:密钥的正确处理逻辑
jwt.io的「Base64 Encoded Secret」选项规则很明确:
- 勾选:输入的密钥字符串是Base64编码后的内容,jwt.io会先对其做Base64解码,得到原始字节数组后再进行HMAC签名验证。
- 不勾选:直接将输入的密钥字符串转成UTF-8字节数组,用于签名验证。
对应JJWT的处理分两种场景:
场景1:对方提供的是明文密钥(非Base64编码)
比如你测试用的"123456789-123456789_123456789_12",当前getSigningKey方法的处理是正确的:
private static Key getSigningKey(String secret) { byte[] theBytes = secret.getBytes(StandardCharsets.UTF_8); SecretKey key = Keys.hmacShaKeyFor(theBytes); return key; }
此时jwt.io验证步骤:
- 把生成的Token粘贴到左侧「Encoded」框。
- 右侧「Verify Signature」输入框填入明文密钥。
- 不要勾选「Base64 Encoded Secret」选项。
场景2:对方提供的是Base64编码后的密钥
比如类似"SGVsbG8gV29ybGQh"这样的字符串,需要先做Base64解码得到原始字节,再传给JJWT:
private static Key getSigningKey(String base64Secret) { // 如果是URL安全的Base64,改用Base64.getUrlDecoder() byte[] decodedBytes = Base64.getDecoder().decode(base64Secret); SecretKey key = Keys.hmacShaKeyFor(decodedBytes); return key; }
此时jwt.io验证步骤:
- 把生成的Token粘贴到左侧「Encoded」框。
- 右侧「Verify Signature」输入框填入Base64编码的密钥字符串。
- 必须勾选「Base64 Encoded Secret」选项。
额外优化建议
- 无需手动设置Header:JJWT的
Jwts.builder()会自动根据签名算法设置alg和typ字段,手动设置反而可能引入拼写错误,建议删除getHeader()方法,使用默认Header。 - 确认Claim字段匹配API要求:目标API要求在载荷中传入API Key,你当前用的是
sub字段,要确认API是否期望这个字段名,还是需要用api_key等其他字段,字段不匹配也会导致API验证失败。
内容的提问来源于stack exchange,提问作者H Ferguson
相关产品推荐
相关产品推荐

