ASP.NET Core中添加角色Claim后,User.FindFirst(ClaimTypes.Role)返回null?
问题原因及解决方案
核心原因
你在OnSigningIn事件中修改了ClaimsPrincipal的角色Claim,但没有更新对应的AuthenticationTicket。ASP.NET Core Cookie认证会基于初始的AuthenticationTicket生成Cookie,修改后的Claim没有被序列化到Cookie中,导致后续请求无法获取到该角色Claim。
解决方案一:更新AuthenticationTicket(适配现有代码)
修改Startup.cs中的OnSigningIn事件处理逻辑,在添加角色Claim后,重新创建并赋值context.Ticket,确保修改后的Principal被写入Cookie:
public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/authentication/signin"; options.Events = new CookieAuthenticationEvents() { OnSigningIn = async context => { var principal = context.Principal; if (principal.HasClaim(c => c.Type == ClaimTypes.Email)) { var email = principal.FindFirstValue(ClaimTypes.Email); var claimsIdentity = principal.Identity as ClaimsIdentity; if (email == "admin@bookevents.com") { claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "Admin")); } else { claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "User")); } // 关键步骤:更新Ticket,保存修改后的Principal context.Ticket = new AuthenticationTicket( principal, context.Ticket.Properties, context.Ticket.AuthenticationScheme); } await Task.CompletedTask; } }; }); services.AddControllersWithViews(); services.AddRazorPages().AddRazorRuntimeCompilation(); }
解决方案二:直接在登录时添加角色Claim(更简洁)
可以跳过OnSigningIn事件,直接在Authentication控制器的Signin方法中创建Claims时添加角色Claim,逻辑更直观且避免Ticket问题:
public async Task<IActionResult> Signin(string email, string password) { var user = userService.Validate(email, password).Data; if (user != null) { var claims = new List<Claim>(); claims.Add(new Claim("email", user.Email)); claims.Add(new Claim(ClaimTypes.Email, user.Email)); claims.Add(new Claim(ClaimTypes.Name, user.FullName)); // 直接添加角色Claim if (user.Email == "admin@bookevents.com") { claims.Add(new Claim(ClaimTypes.Role, "Admin")); } else { claims.Add(new Claim(ClaimTypes.Role, "User")); } var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); await HttpContext.SignInAsync(claimsPrincipal); return Redirect("/BookEvent/ViewAllUserEvents/"); } else { return RedirectToAction("Signin", new { status = 1 }); } }
额外优化:避免空引用异常
在BookEvent控制器中,直接调用Value可能会因为Claim不存在抛出空引用异常,建议先判断Claim是否存在:
public IActionResult ViewAllUserEvents() { string role = User.FindFirstValue(ClaimTypes.Role); if (string.IsNullOrEmpty(role)) { // 处理无角色的情况,比如跳转登录页 return RedirectToAction("Signin", "Authentication"); } string email = User.FindFirstValue(ClaimTypes.Email); IEnumerable<BookEventDTO> enumBook = bookEventsService.GetUserEvents(role, email).Data; return View(enumBook); }
内容的提问来源于stack exchange,提问作者h_21
相关产品推荐
相关产品推荐

