.NET 8 Blazor Server中IClaimsTransformation添加的Claims无法持久化
你遇到的核心问题是:IClaimsTransformation每次处理的ClaimsPrincipal都是从认证Cookie里重新反序列化出来的原始对象,不是上一次修改后留存的实例。
你的认证方案是Cookie+OpenID Connect,用户登录后的身份信息最终存在Cookie中。每次请求(包括Blazor Server的SignalR交互)都会从Cookie读取并反序列化为ClaimsPrincipal,再传给TransformAsync。你之前添加的TEST Claim只存在于当前请求的内存里,没有被持久化到Cookie,所以下一次调用TransformAsync时,传入的principal还是没有TEST Claim的原始状态,自然每次都得重新加。
不管是修改现有身份还是新建身份,只要不把修改后的ClaimsPrincipal写入Cookie,下一次请求都会回到原始状态,这就是两种添加方式都无效的原因。
推荐两种实用的解决办法:
办法一:用Cookie认证的OnValidatePrincipal事件(更推荐)
直接在AddCookie的配置里绑定验证事件,添加Claim后标记更新Cookie,这样修改会被持久化:
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.AccessDeniedPath = "/statuscode/401"; options.Events = new CookieAuthenticationEvents { async OnValidatePrincipal(CookieValidatePrincipalContext context) { if (!context.Principal.HasClaim(c => c.Type == "TEST")) { var identity = context.Principal.Identity as ClaimsIdentity; identity.AddClaim(new Claim("TEST", "TESTVALUE")); // 告诉中间件更新Cookie,把修改后的身份信息存进去 context.ShouldRenew = true; } } }; })
这样处理后,下一次请求加载Cookie时,Principal就已经包含TEST Claim了,不用每次都添加。
办法二:在IClaimsTransformation中手动更新Cookie
给MyClaimsTransformation注入认证服务和HttpContext访问器,添加Claim后重新登录用户以更新Cookie:
public class MyClaimsTransformation : IClaimsTransformation { private readonly IAuthenticationService _authService; private readonly IHttpContextAccessor _httpContextAccessor; public MyClaimsTransformation(IAuthenticationService authService, IHttpContextAccessor httpContextAccessor) { _authService = authService; _httpContextAccessor = httpContextAccessor; } public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { var identity = principal.Identity as ClaimsIdentity; if (identity != null && !principal.HasClaim(c => c.Type == "TEST")) { identity.AddClaim(new Claim("TEST", "TESTVALUE")); // 重新登录,把修改后的身份写入Cookie await _authService.SignInAsync( _httpContextAccessor.HttpContext, CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { IsPersistent = true }); } return principal; } }
⚠️ 注意:一定要加Claim存在性判断,避免SignInAsync触发TransformAsync导致无限循环。
Blazor Server用SignalR长连接,IClaimsTransformation确实会被多次调用,但只要把Claim持久化到Cookie,后续调用时传入的Principal就会自带TEST Claim,不用重复添加。另外你设置了UseTokenLifetime = false,Cookie有效期默认是14天,持久化的Claim会在有效期内一直有效。
内容的提问来源于stack exchange,提问作者Schoof

