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

.NET Core 3.1 JWTBearer认证返回401 Unauthorized问题排查

.NET Core 3.1 JWT认证返回401问题修复

核心问题点

你的代码存在3处直接导致认证失败的问题:

  • 路由模式混用、中间件顺序错误
    你在服务配置中设置EnableEndpointRouting = false关闭了端点路由,要走传统MVC路由逻辑,但管道里同时注册了UseMvc()和UseRouting()/UseEndpoints()两套路由组件,且UseMvc()放在了UseAuthentication()、UseAuthorization()前面。请求进入管道后会先被UseMvc()匹配并进入MVC授权过滤器流程,此时认证中间件还未执行,HttpContext.User没有被JWT处理器填充身份信息,[Authorize]特性直接判定未授权返回401,后续的认证、授权中间件根本不会处理该请求。
  • 服务注册语法错误
    ConfigureServices中services.AddControllers();末尾多写了分号,导致后续.AddMvc()的链式调用完全不生效,MVC配置(包括关闭端点路由的设置)没有正确注入容器,进一步导致路由执行逻辑混乱。
  • Token生成时间隐患
    生成JWT时使用DateTime.Now取本地时间,如果服务器时区和JWT校验逻辑的时区存在偏差,可能出现token刚生成就被判定过期的问题,建议统一使用UTC时间。

修复方案

两种路由模式二选一即可,官方推荐使用端点路由模式,禁止两套路由逻辑混用。

方案1:使用端点路由(推荐)

  1. 修正服务注册代码,移除多余分号,删除关闭端点路由的配置:
public void ConfigureServices(IServiceCollection services)
{
    services
        .AddAuthentication(options => { 
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(options =>
        {
            var key = Encoding.UTF8.GetBytes("thisismycustomSecretkeyforauthentication");
            options.SaveToken = true;
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key)
            };
        });

    services.AddControllers();
}
  1. 修正中间件管道顺序,移除UseMvc(),严格按照端点路由要求的顺序注册:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSpa(spa => spa.UseProxyToSpaDevelopmentServer("https://localhost:22010"));
    }
    else
    {
        app.UseHsts();
    }

    app.UseStaticFiles();
    app.UseHttpsRedirection();
    
    // 端点路由固定顺序:路由匹配 -> 认证 -> 授权 -> 端点执行
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
  1. 修正JWT生成的时间逻辑:
var token = new JwtSecurityToken
(
    issuer: null,
    audience: null,
    claims: new Claim[] { new Claim(ClaimTypes.Name, request.Username) },
    expires: DateTime.UtcNow.AddDays(30),
    signingCredentials: new SigningCredentials(tokenKey, SecurityAlgorithms.HmacSha256)
);

方案2:使用传统MVC路由

如果必须使用传统路由,完全移除UseRouting()、UseEndpoints()相关代码,将认证、授权中间件放在UseMvc()之前注册:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 其他通用中间件(HSTS、HTTPS跳转、静态文件等)保持不变
    app.UseHttpsRedirection();
    // 认证授权必须在MVC路由之前执行
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseMvc(routes => routes.MapRoute(name: "default", template: "{controller=App}/{action=Index}/{id?}"));
    
    if (env.IsDevelopment())
        app.UseSpa(spa => spa.UseProxyToSpaDevelopmentServer("https://localhost:22010"));
}

同时修正ConfigureServices中AddControllers()后的多余分号。

调试手段

如果修复后仍存在问题,可以通过JWT事件监听定位具体失败原因:

.AddJwtBearer(options =>
{
    // 其余配置保持不变
    options.Events = new JwtBearerEvents
    {
        OnAuthenticationFailed = context =>
        {
            // 在此处下断点,查看context.Exception的具体信息,可明确是签名不匹配、token过期、格式错误等具体原因
            return Task.CompletedTask;
        }
    };
});

另外请求受保护接口时,确认请求头中Authorization字段格式正确,为Bearer <你的JWT字符串>,Bearer和token之间需要保留一个空格。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:21:47