You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 21:45:37