Java (JJWT) 中的 Base64 解码不同

Base64 decoded differently in Java (JJWT)

我有一个由某些服务生成的 JWT 令牌,然后在我的 Java 应用程序上进行验证。

问题是由于 base64 解码错误,JJWT 库无法解析 JSON header。

Header Base64 编码:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InRva2VuLXNpZ25pbmcifQ

由 JJWT 解码(归结为调用: new String(javax.xml.bind.DatatypeConverter.parseBase64Binary(myBase64), java.nio.charset.Charset.forName("UTF-8")))):

{"alg":"RS256","typ":"JWT","kid":"token-signing"

所以最后一个大括号丢失了。

然而,当我尝试使用其他解码器时 (https://www.base64decode.org/) - 最后一个花括号就位了。

同样的代码也适用于其他开发人员。

在 Java 中会影响 Base64 解码的特定环境吗?

您收到的 header 是 Base64 without output padding (note that there are 66 characters, which is not a multiple of 4). DatatypeConverter.parseBase64Binary is specified to parse the XML Schema xsd:base64Binary type, which requires output padding。显然它将末尾的 non-padded 字符视为无效字符并简单地忽略它们。

要么使用不同的解码器(Java 8 有 java.util.Base64, Apache Commons.Codec has one, Guava has one too),要么自己填充输出(如果删除所有非 Base64 字符后的字符串长度不能被 4 整除,填充'=' 直到它是)。

JWT 的 header 和负载是 base64 url 编码的,这与 base64 略有不同(替换 +\-,_ 并删除尾随 =)

使用此代码 DatatypeConverter.parseBase64Binary 解码 header 是错误的。需要使用:

java.util.Base64.getUrlDecoder().decode(string);

我查看了 JJWT 的代码并以正确的方式解码了 header。看DefaultJWTSParser第255行

String origValue = TextCodec.BASE64URL.decodeToString(base64UrlEncodedHeader);

可能您正在使用其他库?