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

ASP.NET Core Web API多JWT Bearer令牌身份认证401问题排查

多Identity JWT认证401问题排查与解决方案

问题背景

我正在为ASP.NET Core Web API配置多个.NET Identity认证:

  • 第一个Identity用于集团分支API用户,访问公共服务
  • 每个分支单独配置Identity,用户认证后访问专属服务
  • 用两个不同JWT令牌区分权限

已完成两个Identity的注入配置,但使用[Authorize(AuthenticationSchemes = "Bearer_ApiUser")]限制访问时,能正常获取主Identity令牌,但访问接口返回无详细提示的401错误。移除[Authorize]后接口正常运行。

备注:因分支用户字段/声明差异大、部分用户跨分支,必须保留独立Identity。

现有配置代码

公共Identity注入代码

public static class ApiIdentityServicesRegistration
{
    public static IServiceCollection AddApiIdentityServices(this IServiceCollection services, IConfiguration configuration)
    {
        services.Configure<JwtSettings>(configuration.GetSection("ApiJwtSettings"));
        services.AddDbContext<ApiDbContext>(options =>
        {
            options.UseSqlServer(configuration.GetConnectionString("API_IDENTITY"));
        });

        services.AddIdentity<ApiApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApiDbContext>()
            .AddDefaultTokenProviders();

        services.AddTransient<IApiUserRepository, UserService>();

        services
            .AddAuthentication()
            .AddJwtBearer("Bearer_ApiUser", o =>
        {
            o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero,
                ValidIssuer = configuration["ApiJwtSettings:Issuer"],
                ValidAudience = configuration["ApiJwtSettings:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["ApiJwtSettings:Key"]))
            };
        });
        services.AddAuthorization();

        services.ConfigureApplicationCookie(options =>
        {
            options.Cookie.Name = "AajApiToken";
        });

        return services;
    }
}

分支Identity注入代码

public static class AajIdentityServicesRegistration
{
    public static IServiceCollection AddAajIdentityServices(this IServiceCollection services, IConfiguration configuration)
    {
        services.Configure<JwtSettings>(configuration.GetSection("AajJwtSettings"));
        services.AddDbContext<AajDbContext>(options =>
        {
            options.UseSqlServer(configuration.GetConnectionString("AAJ_IDENTITY"));
        });

        services.AddIdentityCore<AajApplicationUser>()
            .AddEntityFrameworkStores<AajDbContext>()
            .AddDefaultTokenProviders()
            .AddSignInManager<SignInManager<AajApplicationUser>>();

        services.AddTransient<IAajUserRepository, AajUserService>();

        services
            .AddAuthentication()
            .AddJwtBearer("Bearer_AajUser",o =>
        {
            o.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero,
                ValidIssuer = configuration["AajJwtSettingsJwtSettings:Issuer"],
                ValidAudience = configuration["AajJwtSettings:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["AajJwtSettings:Key"]))
            };
        });
        services.ConfigureApplicationCookie(options =>
        {
            options.Cookie.Name = "AajUserToken";
        });
        return services;
    }
}

问题排查步骤

1. 检查配置拼写错误

从分支Identity代码中发现:ValidIssuer = configuration["AajJwtSettingsJwtSettings:Issuer"]存在拼写错误,多写了一个JwtSettings,应改为AajJwtSettings:Issuer。同时需确认公共Identity的配置项名称与appsettings.json完全一致。

2. 启用JWT认证日志

在Program.cs中添加日志过滤配置,查看认证失败的详细原因:

builder.Logging.AddFilter("Microsoft.AspNetCore.Authentication", LogLevel.Debug);

同时在appsettings.json中设置对应日志级别:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.Authentication": "Debug"
    }
  }
}

运行后查看日志,会输出JWT验证失败的具体原因(如签名无效、受众不匹配、颁发者错误等)。

3. 验证令牌内容

使用JWT解析工具解析获取到的令牌,检查:

  • iss字段是否与配置的ValidIssuer一致
  • aud字段是否与配置的ValidAudience一致
  • 签名密钥是否与配置中的ApiJwtSettings:Key一致
  • 令牌是否过期

4. 确认认证中间件顺序

确保在Program.cs中,app.UseAuthentication()在app.UseAuthorization()之前调用,顺序错误会导致认证无效:

app.UseAuthentication();
app.UseAuthorization();

5. 检查认证方案匹配

确认[Authorize(AuthenticationSchemes = "Bearer_ApiUser")]中的方案名称与注册的JWT认证方案名称完全一致(注意大小写),也可显式设置默认认证方案(可选):

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = "Bearer_ApiUser";
    options.DefaultChallengeScheme = "Bearer_ApiUser";
})
.AddJwtBearer("Bearer_ApiUser", o => ...);

6. 检查令牌生成时的声明

确保生成JWT令牌时添加了Identity所需的必要声明(如NameIdentifier、Name等),示例代码:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
    new Claim(ClaimTypes.Name, user.UserName),
    // 添加其他业务所需声明
};

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Key));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
    issuer: jwtSettings.Issuer,
    audience: jwtSettings.Audience,
    claims: claims,
    expires: DateTime.Now.AddMinutes(jwtSettings.ExpiryMinutes),
    signingCredentials: creds);

return new JwtSecurityTokenHandler().WriteToken(token);

总结

优先排查配置拼写错误和令牌内容匹配问题,通过启用认证日志可快速定位401的具体原因,同时确保中间件顺序正确、令牌生成包含必要声明。

内容的提问来源于stack exchange,提问作者Charles M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:28:10