读取JWT声明时西里尔字母编码异常问题求助
问题:JWT中部分声明的西里尔字母显示为\u转义字符
开发了一个接收Webhook的程序,需读取RS256签名的JWT内容。验证公钥已具备,但读取时发现前两个声明(SidePayer、SideRecipient)中的西里尔字母被解析为\u转义字符,后续声明(如purpose)则显示正常。
读取Token代码
public async Task<IActionResult> test() { using (var reader = new StreamReader(Request.Body)) { var body = await reader.ReadToEndAsync(); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters( new RSAParameters() { Modulus = FromBase64Url("rwm77av7GIttq-JF1itEgLCGEZW_zz16RlUQVYlLbJtyRSu61fCec_rroP6PxjXU2uLzUOaGaLgAPeUZAJrGuVp9nryKgbZceHckdHDYgJd9TsdJ1MYUsXaOb9joN9vmsCscBx1lwSlFQyNQsHUsrjuDk-opf6RCuazRQ9gkoDCX70HV8WBMFoVm-YWQKJHZEaIQxg_DU4gMFyKRkDGKsYKA0POL-UgWA1qkg6nHY5BOMKaqxbc5ky87muWB5nNk4mfmsckyFv9j1gBiXLKekA_y4UwG2o1pbOLpJS3bP_c95rm4M9ZBmGXqfOQhbjz8z-s9C11i-jmOQ2ByohS-ST3E5sqBzIsxxrxyQDTw--bZNhzpbciyYW4GfkkqyeYoOPd_84jPTBDKQXssvj8ZOj2XboS77tvEO1n1WlwUzh8HPCJod5_fEgSXuozpJtOggXBv0C2ps7yXlDZf-7Jar0UYc_NJEHJF-xShlqd6Q3sVL02PhSCM-ibn9DN9BKmD"), Exponent = FromBase64Url("AQAB") }); var validationParameters = new TokenValidationParameters { RequireExpirationTime = true, RequireSignedTokens = true, ValidateAudience = false, ValidateIssuer = false, ValidateLifetime = false, IssuerSigningKey = new RsaSecurityKey(rsa) }; SecurityToken validatedSecurityToken; var handler = new JwtSecurityTokenHandler(); handler.ValidateToken(body, validationParameters, out validatedSecurityToken); JwtSecurityToken? validatedJwt = validatedSecurityToken as JwtSecurityToken; if (validatedJwt != null) { foreach (var claim in validatedJwt.Claims.ToList()) { Console.WriteLine($"{claim.Type}: {claim.Value}"); } return Ok(); } else { return BadRequest("Invalid token"); } } } static byte[] FromBase64Url(string base64Url) { string padded = base64Url.Length % 4 == 0 ? base64Url : base64Url + "====".Substring(base64Url.Length % 4); string base64 = padded.Replace("_", "/") .Replace("-", "+"); return Convert.FromBase64String(base64); }
控制台输出
SidePayer: {"bankCode": "000000000", "bankName": "\u041e\u041e\u041e \"\u0411\u0410\u041d\u041a \u0422\u041e\u0427\u041a\u0410\"", "bankCorrespondentAccount": "00000000000000000000", "account": "00000000000000000000", "name": "\u0418\u041f \u0422\u0435\u0441\u0442", "amount": "40.0", "currency": "RUB", "inn": "0000000000", "kpp": "0000000000"} SideRecipient: {"bankCode": "000000000", "bankName": "\u041e\u041e\u041e \"\u0411\u0410\u041d\u041a \u0422\u041e\u0427\u041a\u0410\"", "bankCorrespondentAccount": "00000000000000000000", "account": "00000000000000000000", "name": "\u0418\u041f \u0422\u0435\u0441\u0442", "amount": "40.0", "currency": "RUB", "inn": "0000000000", "kpp": "0000000000"} purpose: Тестовое назначение платежа documentNumber: 00000 date: 2018-10-01
解决方案
问题原因
SidePayer和SideRecipient的声明值是嵌套的JSON字符串,JwtSecurityTokenHandler解析时仅将其作为普通字符串处理,未自动反序列化嵌套结构,导致字符串内的Unicode转义字符(\u开头)未被解码为实际西里尔字母;而purpose等声明是直接的字符串类型,因此显示正常。
解决步骤
针对嵌套JSON类型的声明,手动对其值进行反序列化操作,即可自动解码Unicode转义字符。以下提供两种实现方式:
方式1:使用Newtonsoft.Json(Json.NET)
修改遍历Claims的逻辑,对目标声明进行反序列化:
if (validatedJwt != null) { foreach (var claim in validatedJwt.Claims.ToList()) { if (claim.Type is "SidePayer" or "SideRecipient") { // 反序列化嵌套JSON,自动解码Unicode转义 var decodedObject = Newtonsoft.Json.JsonConvert.DeserializeObject(claim.Value); // 格式化输出,也可直接输出decodedObject var formattedOutput = Newtonsoft.Json.JsonConvert.SerializeObject(decodedObject, Newtonsoft.Json.Formatting.Indented); Console.WriteLine($"{claim.Type}: {formattedOutput}"); } else { Console.WriteLine($"{claim.Type}: {claim.Value}"); } } return Ok(); }
方式2:使用System.Text.Json(.NET Core内置)
若使用.NET Core 3.0+,可直接用内置的Json序列化器:
if (validatedJwt != null) { foreach (var claim in validatedJwt.Claims.ToList()) { if (claim.Type is "SidePayer" or "SideRecipient") { // 反序列化为JsonElement,ToString时自动解码转义 var decodedElement = System.Text.Json.JsonSerializer.Deserialize<System.Text.Json.JsonElement>(claim.Value); Console.WriteLine($"{claim.Type}: {decodedElement.ToString()}"); } else { Console.WriteLine($"{claim.Type}: {claim.Value}"); } } return Ok(); }
额外优化:直接解析整个Payload
如果需要处理多个嵌套JSON声明,也可以直接解析整个JWT的Payload,避免逐个判断:
if (validatedJwt != null) { // 将Payload序列化为JSON字符串 var payloadJson = validatedJwt.Payload.SerializeToJson(); // 反序列化为JObject(Newtonsoft.Json) var payload = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(payloadJson); // 直接访问各声明,自动解码转义字符 Console.WriteLine($"SidePayer: {payload["SidePayer"]}"); Console.WriteLine($"purpose: {payload["purpose"]}"); return Ok(); }
内容的提问来源于stack exchange,提问作者darrso
相关产品推荐
相关产品推荐

