API无法正确获取JWT Token中除ID外的用户信息排查
我正在开发应用的认证模块,用户可成功注册并登录,信息已存入SQL数据库。但在UserController中创建GetCurrentUser方法后,该接口仅能获取到用户ID,其余用户信息均无法正确获取。我已确认Token包含所需的全部用户信息,但接口返回除ID外均为null。
登录方法代码
[HttpPost] [Route("Login")] public async Task<IActionResult> Login(UserLoginRequestModel loginRequest) { var user = await accountService.Validate(loginRequest.Email, loginRequest.Password); if(user == null) { return Unauthorized("Invalid Username or Password"); } var token = GenerateJWT(user); var tokenValue = new { jwt = token }; return Ok(tokenValue); }
GenerateJWT逻辑代码
private string GenerateJWT(UserLoginModel model) { var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, model.Id.ToString()), new Claim(JwtRegisteredClaimNames.GivenName, model.FirstName), new Claim(JwtRegisteredClaimNames.FamilyName, model.LastName), new Claim(JwtRegisteredClaimNames.Email, model.Email), new Claim("language", "english"), }; if (model.DateOfBirth.HasValue) { claims.Add(new Claim(JwtRegisteredClaimNames.Birthdate, model.DateOfBirth.Value.ToShortDateString())); } var identityClaims = new ClaimsIdentity(); identityClaims.AddClaims(claims); var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["PrivateKey"])); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature); var expire = DateTime.UtcNow.AddHours(Convert.ToDouble(configuration["ExpirationHours"])); var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescription = new SecurityTokenDescriptor { Subject = identityClaims, Expires = expire, SigningCredentials = credentials, Issuer = configuration["Issuer"], Audience = configuration["Audience"] }; var token = tokenHandler.CreateToken(tokenDescription); return tokenHandler.WriteToken(token); }
GetCurrentUser接口代码
[HttpGet("current")] [Authorize] // Add authorization attribute to ensure only authenticated users can access this endpoint public async Task<IActionResult> GetCurrentUser() { // Retrieve the authenticated user's information from the JWT token's claims var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var firstName = User.FindFirst(JwtRegisteredClaimNames.GivenName)?.Value; var lastName = User.FindFirst(JwtRegisteredClaimNames.FamilyName)?.Value; var email = User.FindFirst(JwtRegisteredClaimNames.Email)?.Value; var dateOfBirth = User.FindFirst(JwtRegisteredClaimNames.Birthdate)?.Value; var token = Request.Headers["Authorization"].ToString().Replace("Bearer ", ""); // Create a response object with the user information var currentUser = new CurrentUserModel { Id = int.Parse(userId), FirstName = firstName, LastName = lastName, Email = email, DateOfBirth = !string.IsNullOrEmpty(dateOfBirth) ? DateTime.Parse(dateOfBirth) : null }; logger.LogInformation($"JWT Token: {token}"); return Ok(currentUser); }
可能的问题及解决方法
JWT认证配置未正确映射声明
ASP.NET Core默认不会自动将JwtRegisteredClaimNames下的声明映射到User对象的Claims集合。需要在Startup/Program.cs的认证配置中添加声明映射逻辑:services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = configuration["Issuer"], ValidAudience = configuration["Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["PrivateKey"])), SaveSigninToken = true }; options.Events = new JwtBearerEvents { OnTokenValidated = context => { var claimsIdentity = context.Principal.Identity as ClaimsIdentity; if (claimsIdentity != null) { // 将JWT中所有声明添加到Identity foreach (var claim in context.SecurityToken.Claims) { if (!claimsIdentity.HasClaim(c => c.Type == claim.Type)) { claimsIdentity.AddClaim(claim); } } } return Task.CompletedTask; } }; });声明类型不匹配
JwtRegisteredClaimNames.GivenName对应的字符串是"given_name",而ClaimTypes.GivenName是"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",两者类型不同。你生成Token时用的是前者,但获取时如果配置默认映射了后者,就会找不到值。- 解决方法1:获取声明时直接用字符串类型,比如
User.FindFirst("given_name") - 解决方法2:生成Token时改用
ClaimTypes对应类型:var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, model.Id.ToString()), new Claim(ClaimTypes.GivenName, model.FirstName), new Claim(ClaimTypes.Surname, model.LastName), new Claim(ClaimTypes.Email, model.Email), new Claim("language", "english"), };
- 解决方法1:获取声明时直接用字符串类型,比如
Token验证参数不一致
确保TokenValidationParameters中的ValidIssuer、ValidAudience、IssuerSigningKey和生成Token时的配置完全一致,否则Token会被部分验证,导致声明无法解析。前端请求Token完整性
检查前端调用GetCurrentUser接口时,是否正确将完整Token放在Authorization头中(格式为Bearer {token}),可通过后端日志打印的token值再次解码验证。
内容的提问来源于stack exchange,提问作者Corey Sutton

