升级至Duende Identity Server后JWT Claims出现转义字符异常
问题原因
- 双重序列化触发转义:升级到Duende Identity Server和.NET 6后,Claim的处理逻辑发生变化。你手动将
appClaims序列化为JSON字符串并指定Claim类型为JsonClaimValueTypes.JsonArray,但系统会对该字符串再次执行序列化——把原本的JSON结构当成普通字符串处理,最终导致双引号被转义成\"。 - .NET 6序列化行为变更:.NET 6的
System.Text.Json默认配置与.NET Core 3.x存在差异,即使序列化代码未修改,输出的JSON字符串在后续流程中也更容易被重复转义。
解决方法
方案1:正确传递JSON结构(推荐)
不要手动序列化对象,使用JsonSerializer.SerializeToElement将appClaims转为JsonElement,再取其原始JSON文本作为Claim值。这样系统能识别这是JSON数组,不会重复序列化:
// 替换原序列化+添加Claim的代码 var jsonElement = JsonSerializer.SerializeToElement(appClaims); claims.Add(new Claim(AppClaims, jsonElement.GetRawText(), JsonClaimValueTypes.JsonArray));
方案2:改用普通字符串类型(临时兼容)
如果暂时不想调整序列化逻辑,可以去掉JsonClaimValueTypes.JsonArray参数,让Claim按普通字符串处理。下游校验时,JsonSerializer.Deserialize会自动处理转义符,无需手动调用Replace("\\", ""):
claims.Add(new Claim(AppClaims, JsonSerializer.Serialize(appClaims)));
方案3:修复异步代码的阻塞问题(潜在风险)
你的代码中使用Select(x => x.Result)同步阻塞获取异步任务结果,在.NET 6中容易引发死锁或异常,建议改成标准异步写法:
// 替换原appClaims赋值代码 appClaims = await Task.WhenAll(userPermissions.Select(async x => new AppClaim { Claims = x.AppRoleId != null ? await GetRoleClaims(x.AppRoleId, x.AppClaims) : x.Claims.Split(sepChar), AppName = x.AppName, Instance = x.Name }));
验证方式
生成JWT后解码payload,确认AppClaims是纯JSON数组格式,而非带转义符的字符串:
"AppClaims": [{"AppName":"TTU","Instance":"TTU-dev-solihull","Claims":["StrategyManager-R","StrategyManager-RW",...]}]
内容的提问来源于stack exchange,提问作者Umair_007
相关产品推荐
相关产品推荐

