在.NET 8路由中获取当前用户信息的问题排查
.NET 8 JWT认证问题:HttpContext.User为空无法获取ChurchId
问题描述
在.NET 8开发接口时,已通过JWT实现登录并存储用户信息,但在allMembers路由中,HttpContext.User返回null且IsAuthenticated为false,无法获取用户的ChurchId。用户与教会为一对多关系,教会与成员为一对多关系,需要根据当前登录用户的ChurchId查询对应教会的所有成员。前端采用React,尝试前端过滤未得到预期结果,需从后端解决该问题。
登录路由代码
[HttpPost] [Route("Login")] public async Task<IActionResult> Login([FromBody]LoginModel login) { if(ModelState.IsValid) { var existing_user = await _userManager.FindByNameAsync(login.UserName); if(existing_user == null) return BadRequest(new AuthResult() { Status = "Failed", Result = false, Message = "Please Create a user", Errors = new List<string>() { "User doesn't exist" } }); var result = await _userManager.CheckPasswordAsync(existing_user, login.Password); if (result) { existing_user.LastLoggedOn = DateTime.UtcNow; await _userManager.UpdateAsync(existing_user); // Log the successful login with ChurchId _logger.LogInformation("User {UserName} successfully logged in with ChurchId {ChurchId}.", existing_user.UserName, existing_user.ChurchId); var jwtToken = GenerateJwtToken(existing_user); // Return a successful response with the JWT token return Ok(new AuthResult() { Token = jwtToken, Result = true, Status = "Success", Message ="Login was Successful;" }); } } else { ModelState.AddModelError(string.Empty, "Invalid login attempt."); return BadRequest(new AuthResult() { Status = "Failed", Result = false, Message = "Login was unsuccessful", Errors = new List<string>() { "Invalid Login Attempt" } }); } return BadRequest(); }
allMembers路由代码
[HttpGet] [Route("allMembers")] public async Task<IActionResult> GetAllMembers() { // Inspect HttpContext.User for debugging var user = HttpContext.User; var token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); _logger.LogInformation($"Received token: {token}"); if (user != null) { _logger.LogInformation($"User Information - Name: {user.Identity.Name}, IsAuthenticated: {user.Identity.IsAuthenticated}"); // Log all claims for debugging foreach (var claim in user.Claims) { _logger.LogInformation($"Claim Type: {claim.Type}, Claim Value: {claim.Value}"); } // Check if ChurchId claim exists and is not null or empty var churchIdClaim = user.FindFirst("ChurchId"); if (churchIdClaim == null || string.IsNullOrEmpty(churchIdClaim.Value)) { // Log the issue for debugging _logger.LogError("Invalid or missing ChurchId claim. User: {UserName}"); // Handle the case where ChurchId is null or empty // You might want to return an error or handle this case as needed return BadRequest(new { message = "Invalid or missing ChurchId claim." }); } // Use the extracted ChurchId directly in your service method var currentUserChurchId = churchIdClaim.Value; try { // Now you can use currentUserChurchId in your service method var members = await _memberService.GetMembersAsync(currentUserChurchId); return Ok(members); } catch (Exception ex) { _logger.LogError(ex, "Error retrieving members for ChurchId {ChurchId}. User: {UserName}", currentUserChurchId, user.Identity.Name); return StatusCode(500, "Internal Server Error"); } } else { // Log an error or handle the case where the user object is null _logger.LogError("HttpContext.User is null."); return BadRequest(new { message = "Invalid or missing user information." }); } }
解决方案
1. 添加[Authorize]特性到allMembers路由
未添加认证特性的话,ASP.NET Core不会对该路由进行JWT认证,导致HttpContext.User未被填充。修改路由代码:
[HttpGet] [Route("allMembers")] [Authorize] // 新增该特性 public async Task<IActionResult> GetAllMembers() { // 原有代码不变 }
2. 检查Program.cs中的JWT中间件配置
确保认证中间件已正确配置,且顺序正确(UseAuthentication必须在UseAuthorization之前,且都在UseRouting之后,UseEndpoints之前):
var builder = WebApplication.CreateBuilder(args); // 添加JWT认证服务 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], // 需与生成Token时一致 ValidAudience = builder.Configuration["Jwt:Audience"], // 需与生成Token时一致 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) // 需与生成Token时一致 }; }); // 添加授权服务 builder.Services.AddAuthorization(); var app = builder.Build(); // 中间件顺序必须正确 app.UseRouting(); app.UseAuthentication(); // 认证中间件 app.UseAuthorization(); // 授权中间件 app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.Run();
3. 确保GenerateJwtToken方法正确添加ChurchId声明
检查生成JWT的方法,确认已将ChurchId添加到Claims中:
private string GenerateJwtToken(ApplicationUser user) { var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.UserName), new Claim("ChurchId", user.ChurchId.ToString()), // 必须添加该声明 // 其他必要声明 }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _configuration["Jwt:Issuer"], audience: _configuration["Jwt:Audience"], claims: claims, expires: DateTime.Now.AddMinutes(30), // 按需设置过期时间 signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); }
4. 验证前端请求是否正确携带Token
确保React前端在请求allMembers接口时,正确在请求头中添加Authorization字段,格式为Bearer <你的JWT Token>:
// React示例代码 async function getAllMembers() { const token = localStorage.getItem('jwtToken'); // 假设Token存在localStorage中 const response = await fetch('/api/yourController/allMembers', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, // 注意Bearer后有空格 'Content-Type': 'application/json' } }); const data = await response.json(); // 处理返回数据 }
内容的提问来源于stack exchange,提问作者Timmy
相关产品推荐
相关产品推荐

