Claims值返回null求助:ASP.NET登录后无法获取自定义Claims
Claims添加成功但检索返回null的问题排查
在Web应用的Account控制器Login动作内,编写了验证用户名密码正确性并向Claims中加载数据的代码。逐行调试时显示数据已成功添加至Claims,但尝试检索这些Claims时却返回null。
相关代码
登录添加Claims的代码
public void SignInUser(string username, string userRole, string userid, bool isPersistent, string UserLevel, string User_Company, string EmpName, string DepId) { // Initialization. var claims = new List < Claim > (); try { // Setting claims.Add(new Claim(ClaimTypes.Name, username)); claims.Add(new Claim(ClaimTypes.Role, userRole)); claims.Add(new Claim("UserId", userid)); claims.Add(new Claim("UserLevel", UserLevel)); claims.Add(new Claim("CompanyID", User_Company)); claims.Add(new Claim("EmpName", EmpName)); claims.Add(new Claim("DepId", DepId)); var claimIdenties = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie); var ctx = Request.GetOwinContext(); var authenticationManager = ctx.Authentication; // Sign In. authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, claimIdenties); var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie); var claimsPrincipal = new ClaimsPrincipal(identity); Thread.CurrentPrincipal = claimsPrincipal; } catch (Exception ex) { // Info throw ex; } }
检索Claims的代码
var UsrLvl = (User.Identity as ClaimsIdentity).Claims.Where(c => c.Type == "UserLevel").FirstOrDefault(); var UsrID = (User.Identity as ClaimsIdentity).Claims.Where(c => c.Type == "UserId").FirstOrDefault(); var UserDep = (User.Identity as ClaimsIdentity).Claims.Where(c => c.Type == "DepId").FirstOrDefault();
问题现象
- 数据传入时Claims已正确添加:

- 检索时返回null:

问题原因及解决方法
核心问题1:重复创建身份对象且未利用Owin认证上下文
代码中在调用authenticationManager.SignIn后,又重复创建了ClaimsIdentity和ClaimsPrincipal并设置Thread.CurrentPrincipal,但当前请求的User.Identity并不会立刻更新——User是当前请求上下文的对象,只有下一个请求才会从认证Cookie中读取新的Claims身份。同时在Web环境下,Thread.CurrentPrincipal的作用范围有限,每个请求对应独立线程,不能依赖它来更新当前请求的身份。
核心问题2:同一请求内尝试检索新添加的Claims
如果在调用SignInUser后,立刻在同一个Login动作里执行检索Claims的代码,此时User.Identity还是登录前的旧身份,自然找不到新添加的Claims。
修复步骤
- 简化SignInUser代码:移除重复创建身份对象的冗余代码,只保留Owin认证管理器的SignIn逻辑:
public void SignInUser(string username, string userRole, string userid, bool isPersistent, string UserLevel, string User_Company, string EmpName, string DepId) { var claims = new List<Claim>(); try { claims.Add(new Claim(ClaimTypes.Name, username)); claims.Add(new Claim(ClaimTypes.Role, userRole)); claims.Add(new Claim("UserId", userid)); claims.Add(new Claim("UserLevel", UserLevel)); claims.Add(new Claim("CompanyID", User_Company)); claims.Add(new Claim("EmpName", EmpName)); claims.Add(new Claim("DepId", DepId)); var claimIdentity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie); var ctx = Request.GetOwinContext(); var authenticationManager = ctx.Authentication; authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, claimIdentity); } catch (Exception ex) { throw ex; } }
登录后重定向到其他Action再检索Claims:
在Login动作完成验证和SignIn后,执行重定向(比如return RedirectToAction("Index", "Home")),然后在目标Action(如Home/Index)中执行检索Claims的代码。优化检索代码:使用
FindFirst方法简化检索逻辑,同时增加空值判断避免异常:
var usrLvl = (User.Identity as ClaimsIdentity)?.FindFirst("UserLevel"); var usrID = (User.Identity as ClaimsIdentity)?.FindFirst("UserId"); var userDep = (User.Identity as ClaimsIdentity)?.FindFirst("DepId");
- 确认Owin中间件配置正确:
在Startup.cs中确保已启用Cookie认证中间件:
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login") });
内容的提问来源于stack exchange,提问作者Dev Beginner
相关产品推荐
相关产品推荐

