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

在.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:20:58