.NET Core中IClaimsTransformation添加的Claims刷新后丢失问题
问题背景
参照微软官方.NET Core Claims相关教程实现自定义声明扩展功能,已完成IClaimsTransformation实现类编写与Program.cs服务注册,运行时代码if (!principal.HasClaim(claim => claim.Type == claimType))判断结果始终为true,页面刷新后ClaimsPrincipal中始终不存在此前添加的声明。
核心原因及排查方案
服务注册生命周期配置错误
IClaimsTransformation实现类必须注册为单例生命周期,若错误注册为Scoped或Transient,会导致每次请求触发转换时生成新实例,追加的声明无法写入身份认证Cookie做持久化,每次请求都会重复进入“判断声明不存在->追加声明”的逻辑,但声明不会被保留。
正确注册代码示例:builder.Services.AddSingleton<IClaimsTransformation, YourCustomClaimsTransformation>();TransformAsync方法实现逻辑错误
实现转换方法时,若只是临时修改传入的ClaimsPrincipal但未将修改后的主体作为返回值返回,或是新建ClaimsIdentity后未正确附加到主体上,会导致认证中间件拿到的仍是原始未修改的主体,追加的声明自然不会生效。
正确实现参考:public class CustomClaimsTransformation : IClaimsTransformation { public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { const string customClaimType = "your_custom_claim_type"; // 避免重复添加声明 if (!principal.HasClaim(c => c.Type == customClaimType)) { var identity = new ClaimsIdentity(); identity.AddClaim(new Claim(customClaimType, "your_claim_value")); principal.AddIdentity(identity); } return Task.FromResult(principal); } }Cookie认证默认声明裁剪过滤了自定义声明
.NET Core Cookie认证默认会对写入Cookie的声明做裁剪,未在配置中显式映射的自定义声明会被直接过滤,即使转换逻辑中追加成功,写入Cookie时也会被丢弃,下次请求从Cookie加载身份信息时自然找不到对应声明。需要在认证配置中显式映射需要保留的自定义声明:builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { // 显式映射自定义声明,避免被裁剪 options.ClaimActions.MapKey(customClaimType, customClaimType); });声明类型匹配规则不匹配
HasClaim方法对Claim.Type的匹配默认区分大小写,若添加声明时的Type字符串和判断时的字符串存在大小写偏差,或是被框架自动映射为带XML命名空间前缀的全限定声明名,也会导致判断时找不到对应声明。可以在调试时遍历principal.Claims集合,打印所有声明的实际Type值做比对确认。
内容的提问来源于stack exchange,提问作者MG123

