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

.NET 7 API携带有效JWT Token仍返回401问题排查与解决

.NET 7 API JWT认证添加[Authorize]后返回401的解决方法

问题场景

配置.NET 7 API启用JWT令牌认证时,未添加[Authorize]特性的端点可正常响应,但添加该特性的端点始终返回401 Unauthorized。已尝试关闭Issuer和Audience验证,且确认app.UseAuthentication()与app.UseAuthorization()的调用顺序无误,生成的Token格式看似正常,但用Postman请求受保护端点始终无法通过认证。

相关配置代码

JWT扩展配置类

public static class AuthenticationExtension
{
    public static void AddAuthentication(this IServiceCollection services, IConfiguration configuration)
    {
        var jwtAppSettingOptions = configuration.GetSection(nameof(JwtOptions));
        var securityKey = jwtAppSettingOptions[(nameof(JwtOptions.SecurityKey))]?.Trim() ?? string.Empty;
        var jwtSecurityKey = Encoding.ASCII.GetBytes(securityKey);
        var symmetricSecurityKey = new SymmetricSecurityKey(jwtSecurityKey);
        var tokenValidationsParameters = new TokenValidationParameters()
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = symmetricSecurityKey,
            ValidateIssuer = false,
            ValidIssuer = jwtAppSettingOptions[(nameof(JwtOptions.Issuer))]?.Trim() ?? string.Empty,
            ValidateAudience = false,
            ValidAudience = jwtAppSettingOptions[(nameof(JwtOptions.Audiance))]?.Trim() ?? string.Empty,
            ValidateLifetime = true,
            RequireExpirationTime = true,
            ClockSkew = TimeSpan.FromMinutes(10),
        };

        services.Configure<JwtOptions>(options =>
        {
            options.Issuer = jwtAppSettingOptions[(nameof(JwtOptions.Issuer))]?.Trim() ?? string.Empty;
            options.Audiance = jwtAppSettingOptions[(nameof(JwtOptions.Audiance))]?.Trim() ?? string.Empty;
            options.SigningCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256Signature);
            options.AccessTokenExpiration = uint.Parse(jwtAppSettingOptions[nameof(JwtOptions.AccessTokenExpiration)] ?? "0");
            options.RefreshTokenExpiration = uint.Parse(jwtAppSettingOptions[nameof(JwtOptions.RefreshTokenExpiration)] ?? "0");
        });

        services.Configure<IdentityOptions>(options =>
        {
            options.Password.RequireDigit = true;
            options.Password.RequireLowercase = true;
            options.Password.RequireUppercase = true;
            options.Password.RequireNonAlphanumeric = true;
            options.Password.RequiredLength = 6;
        });

        services
            .AddAuthentication(options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = tokenValidationsParameters;
            });
    }
}

Program.cs配置

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddCors();
        builder.Services.AddControllers();
        builder.Services.AddRouting(options => options.LowercaseUrls = true);
        builder.Services.AddSwagger();
        builder.Services.AddAuthentication(builder.Configuration);
        builder.Services.RegisterDependencies(builder.Configuration);

        var app = builder.Build();

        app.UseSwaggerUI();
        app.UseHttpsRedirection();
        app.UseCors(builder => builder
            .SetIsOriginAllowed(orign => true)
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());
        app.UseAuthentication();
        app.UseAuthorization();
        app.MapControllers();

        app.Run();
    }
}

受保护端点代码

[HttpGet]
[Authorize]
public IActionResult Ping() => Ok("Success");

Token生成代码

private async Task<UsuarioDTO.AutenticarRetorno> ObterRetornoAutenticadoAsync(string email)
{
    var usuario = await ObterUsuarioAsync(email);
    var claims = await ObterClaimsAsync(usuario);
    var dataExpiracao = DateTime.Now.AddHours(_options.AccessTokenExpiration);
    var securityTokenDescriptior = new SecurityTokenDescriptor()
    {
        Subject = new ClaimsIdentity(claims),
        Issuer = _options.Issuer,
        Audience = _options.Audiance,
        Expires = dataExpiracao,
        NotBefore = DateTime.Now,
        SigningCredentials = _options.SigningCredentials,
    };

    var jwt = _handler.CreateToken(securityTokenDescriptior);
    var token = _handler.WriteToken(jwt);

    return new UsuarioDTO.AutenticarRetorno(token, dataExpiracao);
}

排查与解决方案

通过给AddJwtBearer配置添加JwtBearerEvents并设置断点调试,发现认证过程中存在底层依赖缺失的错误。最终在Web API项目中安装System.IdentityModel.Tokens.Jwt NuGet包后,问题得到解决,带[Authorize]特性的端点可正常通过JWT认证并返回响应。

内容的提问来源于stack exchange,提问作者Juliano Maciel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:24:55