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

JWT认证中ClaimsPrincipal多身份及IsAuthenticated=false问题排查

解决方案

一、解决多身份与IsAuthenticated=false问题

核心原因是IdentityCore默认认证方案(Cookie)与JWT认证方案冲突,导致两个认证中间件同时处理请求,一个验证成功(JWT)、一个验证失败(未配置Cookie),从而生成多个身份。

1. 统一认证方案配置

修改Program.cs中的认证服务配置,将默认认证方案设为JWT,避免Identity的Cookie认证干扰:

// 配置IdentityCore(仅用于用户管理,不做默认认证)
builder.Services.AddIdentityCore<ApplicationUser>(options =>
{
    // 按需配置密码、用户验证规则
})
.AddEntityFrameworkStores<ApplicationDbContext>();

// 配置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"],
        ValidAudience = builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
    };
});

builder.Services.AddAuthorization();

2. 修正Logout端点认证

JWT场景下,Logout无需服务端销毁令牌(客户端删除本地令牌即可)。若需服务端注销(如令牌黑名单),需明确指定JWT认证方案保护端点:

[HttpPost("logout")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<IActionResult> Logout()
{
    // 可选:将令牌加入黑名单(如存入Redis)
    var token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
    await _redisCache.SetStringAsync($"Blacklist:{token}", "revoked", 
        new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) });
    
    return Ok("Logout successful");
}

二、解决自定义Claims不生效问题

自定义Claims需同时实现ClaimsPrincipalFactory扩展和JWT令牌生成时的Claims注入。

1. 实现自定义UserClaimsPrincipalFactory

public class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    public CustomUserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, IOptions<IdentityOptions> optionsAccessor)
        : base(userManager, optionsAccessor)
    {
    }

    protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
        var identity = await base.GenerateClaimsAsync(user);
        // 添加自定义Claims
        identity.AddClaim(new Claim("UserFullName", user.FullName));
        identity.AddClaim(new Claim(ClaimTypes.Role, user.Role));
        return identity;
    }
}

2. 注册自定义Factory并生成含Claims的JWT

在Program.cs中替换默认Factory:

builder.Services.AddIdentityCore<ApplicationUser>(options =>
{
    // 配置项
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddClaimsPrincipalFactory<CustomUserClaimsPrincipalFactory>(); // 注册自定义Factory

登录时从UserManager获取包含自定义Claims的主体,注入到JWT中:

[HttpPost("login")]
public async Task<IActionResult> Login(LoginModel model)
{
    var user = await _userManager.FindByEmailAsync(model.Email);
    if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
    {
        // 获取含自定义Claims的ClaimsPrincipal
        var claimsPrincipal = await _userManager.CreateUserPrincipalAsync(user);
        var claims = claimsPrincipal.Claims.ToList();

        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Expires = DateTime.UtcNow.AddHours(1),
            Issuer = _configuration["Jwt:Issuer"],
            Audience = _configuration["Jwt:Audience"],
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        return Ok(new { Token = tokenHandler.WriteToken(token) });
    }
    return Unauthorized();
}

三、关键检查项

  • 确保中间件顺序正确:app.UseAuthentication()必须在app.UseAuthorization()之前,且仅调用一次。
  • 避免同时启用多个默认认证方案,如需支持多认证方式,在[Authorize]属性中明确指定方案(如[Authorize(AuthenticationSchemes = "JwtBearer,Cookies")])。

内容的提问来源于stack exchange,提问作者Nasser X

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:22:42