从对象存储获取Base64格式JWT后解码失败,请求DataWeave错误排查
这个报错的根源很明确:你直接把整个JWT令牌传给fromBase64()函数,但JWT本身不是纯Base64字符串——它是由三个Base64URL编码的片段(头部、载荷、签名)用点(.)拼接而成的,而点字符(ASCII码2e)不在标准Base64的字符集里,所以函数会抛出非法字符的错误。
要正确解码JWT,你需要先拆分令牌,再对每个片段做Base64URL解码(注意Base64URL和标准Base64的细微区别),最后把头部和载荷转换成JSON结构。下面是一步步的解决方案:
步骤1:理解JWT的结构
你的JWT令牌是:eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiIxNzMzIiwiVXNlck5hbWUiOiJhY2hhbjAzMiIsIkN1bHR1cmVUYWciOm51bGwsImlhdCI6IjE1Njc2Njk3MDgiLCJleHAiOiIxNTY3NzU2MTA4IiwiaXNzIjoiVGltZVNoYXJlV2FyZSIsImF1ZCI6Imh0dHBzOi8vVGltZVNoYXJlV2FyZS5jb20vIn0.w2h6j7gbAs6CouE9WoYEDQRzBYEsNIqry70w2K4JAZg
用.拆分后得到三个部分:
- 头部:
eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9 - 载荷:
eyJVc2VySUQiOiIxNzMzIiwiVXNlck5hbWUiOiJhY2hhbjAzMiIsIkN1bHR1cmVUYWciOm51bGwsImlhdCI6IjE1Njc2Njk3MDgiLCJleHAiOiIxNTY3NzU2MTA4IiwiaXNzIjoiVGltZVNoYXJlV2FyZSIsImF1ZCI6Imh0dHBzOi8vVGltZVNoYXJlV2FyZS5jb20vIn0 - 签名:
w2h6j7gbAs6CouE9WoYEDQRzBYEsNIqry70w2K4JAZg
步骤2:编写DataWeave脚本解码
下面的脚本会自动拆分JWT,处理Base64URL到标准Base64的转换,然后解码并转成JSON:
%dw 2.0 import * from dw::core::Binaries import * from dw::core::Strings output application/json // 自定义函数:处理Base64URL解码(替换特殊字符+补填充) fun base64UrlDecode(str: String): String = fromBase64( // 将Base64URL的"-"和"_"替换为标准Base64的"+"和"/" (str replace "-" with "+" replace "_" with "/") // 补充Base64需要的"="填充字符 ++ (if ((str length mod 4) > 0) ("=" * (4 - (str length mod 4))) else "") ) as String // 拆分JWT为三个部分 var jwtSegments = payload as String splitBy "." --- { // 解码头部并转成JSON header: base64UrlDecode(jwtSegments[0]) read application/json, // 解码载荷并转成JSON payload: base64UrlDecode(jwtSegments[1]) read application/json, // 解码签名(转成字符串方便查看,也可以保留Binary类型) signature: fromBase64( (jwtSegments[2] replace "-" with "+" replace "_" with "/") ++ (if ((jwtSegments[2] length mod 4) > 0) ("=" * (4 - (jwtSegments[2] length mod 4))) else "") ) as Binary as String }
运行结果
执行这个脚本后,你会得到符合预期的结构:
{ "header": { "alg": "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256", "typ": "JWT" }, "payload": { "UserID": "1733", "UserName": "achan032", "CultureTag": null, "iat": "1567669708", "exp": "1567756108", "iss": "TimeShareWare", "aud": "https://TimeShareWare.com/" }, "signature": "w2h6j7gbAs6CouE9WoYEDQRzBYEsNIqry70w2K4JAZg" }
额外提示
如果你只需要头部和载荷(签名通常用于验证,不需要解析内容),可以去掉签名部分的处理,简化脚本。另外,注意JWT的载荷是明文编码的,不需要密钥就能解码,这是正常的设计——签名才是用来验证内容完整性的。
内容的提问来源于stack exchange,提问作者Rishul Saxena

