PAYATHON 2026

.NET 7 API 使用 JWT 时是否仍需显式配置身份验证和授权中间件?

技术老齐

结论:取决于启动方式

在 .NET 7 中,使用 WebApplication.CreateBuilder(args) 创建应用时,框架会在检测到相关服务后自动添加身份验证和授权中间件,因此可以省略显式调用 UseAuthentication() 和 UseAuthorization()。Microsoft 的 Minimal API 身份验证和授权文档说明了这一行为。

题目中的代码使用的是:

Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    });

这是传统的 Startup 启动方式,不适用 WebApplication 的自动添加规则。除非项目中的其他组件已经添加了这两个中间件,否则仍应在 Startup.Configure 中显式配置。

自动添加机制适用于 WebApplication 托管模型,与是否使用 JWT 无关。使用该托管模型的 Controller API 同样适用,不限于通过 MapGet 等方法定义的 Minimal API。

服务注册和中间件配置有什么区别?

API作用
AddAuthentication()、AddJwtBearer()注册身份验证服务、JWT Bearer 处理程序及其配置
AddAuthorization()注册授权服务及策略
UseAuthentication()将身份验证中间件加入请求管道
UseAuthorization()将授权中间件加入请求管道

WebApplication 会检查服务容器,分别判断是否需要自动添加中间件:

  • 检测到 IAuthenticationSchemeProvider,且应用没有显式调用 UseAuthentication() 时,自动添加身份验证中间件。
  • 检测到 IAuthorizationHandlerProvider,且应用没有显式调用 UseAuthorization() 时,自动添加授权中间件。

这些服务通常分别由 AddAuthentication() 和 AddAuthorization() 注册,具体判断见 ASP.NET Core 7.0 的 WebApplicationBuilder 源码。满足上述条件时,即使省略调用,中间件仍会由框架添加并执行。

使用 WebApplication 时如何配置?

下面的示例通过自动添加机制保护 /private 接口:

using Microsoft.AspNetCore.Authentication.JwtBearer;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = builder.Configuration["Jwt:Authority"];
        options.Audience = builder.Configuration["Jwt:Audience"];
    });

builder.Services.AddAuthorization();

var app = builder.Build();

app.MapGet("/public", () => Results.Ok("Public"));

app.MapGet("/private", () => Results.Ok("Authenticated"))
    .RequireAuthorization();

app.Run();

项目需要引用与 .NET 7 兼容的 Microsoft.AspNetCore.Authentication.JwtBearer 包,并提供有效的 Jwt:Authority 和 Jwt:Audience 配置。示例假定令牌颁发方提供可用的元数据和签名密钥发现端点。自签发 JWT 的项目需要按自己的签发方式配置验证参数。

这里的 RequireAuthorization() 不能省略,因为注册身份验证和授权服务不会自动保护所有接口。Controller API 通常通过 [Authorize] 声明访问要求,也可以配置全局要求认证的 FallbackPolicy。相关说明见 Microsoft 的身份验证概述。

继续使用 Startup 时如何配置?

对于题目中的 UseStartup<Startup>(),应保留 ConfigureServices 中的 JWT 和授权服务注册,并在 Configure 中按以下顺序配置中间件:

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

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

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

这里假定 ConfigureServices 已调用 AddControllers()、AddAuthentication(...).AddJwtBearer(...) 和 AddAuthorization(),并完成 JWT 验证配置。

身份验证应先于授权执行,让授权中间件能够使用已经建立的用户身份;授权检查则应在端点执行前完成。Microsoft 的中间件文档给出了这一顺序。

如果删除这两个调用后应用仍然“正常”,仅凭给出的 Program.cs 无法确定原因。需要检查实际执行的 Startup.Configure、项目封装的中间件扩展方法,以及是否有 IStartupFilter 等组件代为添加中间件。官方启动文档说明,IStartupFilter 可以替应用添加中间件。

哪些情况下应该显式调用?

需要控制中间件顺序时,应显式调用。例如,启用 CORS 的应用可以这样配置:

app.UseRouting();

app.UseCors("ApiCors");
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

这段代码适用于 WebApplication,前提是已注册名为 ApiCors 的 CORS 策略及 Controller 服务。Microsoft 的身份验证和授权文档也以 CORS 为例,说明了显式配置顺序的必要性。

如果自定义中间件需要读取认证后的 HttpContext.User,应将它放在 UseAuthentication() 之后;如果还需要在授权检查前参与处理,则应放在 UseAuthorization() 之前。

在 WebApplication 中显式调用这些方法后,框架会识别已添加的中间件,不再自动添加对应项。因此,可以保留这些调用来明确中间件顺序。

如何确认 JWT 保护确实生效?

仅测试携带有效 Token 能否访问接口还不够,因为公开接口也可能返回相同结果。应选择一个明确要求身份验证的接口,至少检查以下情况:

请求情况默认 JWT Bearer 行为下的预期结果
未携带 Token401 Unauthorized
Token 过期、签名无效,或不满足配置的颁发方、受众要求401 Unauthorized
Token 有效且满足授权要求正常进入接口
Token 有效,但不满足接口要求的角色或权限策略403 Forbidden

这些预期以未自定义认证事件或授权响应处理为前提。还应检查接口是否标注了 [AllowAnonymous],以及请求是否实际命中了预期的受保护端点。身份验证中的 challenge 和 forbid 行为可参见 Microsoft 身份验证概述。

这与 .NET 7 的默认身份验证方案变化有关吗?

.NET 7 还有一项容易与此混淆的变化:当应用只注册一个身份验证方案时,框架默认会将它作为默认方案。因此,单方案场景下可能不再需要向 AddAuthentication() 传入方案名称。多个方案并存时,则需要明确配置默认方案,或在授权策略中指定使用哪个方案。参见默认身份验证方案变更说明。

默认方案选择与自动添加中间件相互独立,不能据此判断传统 Startup 管道可以省略中间件。

自动添加机制是有意设计的行为,有官方文档和 .NET 7 源码依据。对于当前项目,简单的 WebApplication 管道可以采用自动配置;传统 Startup 管道或有顺序要求的应用,应显式配置。升级到更高版本时,应核对目标版本文档,并重新验证未登录、无效 Token 和权限不足时的请求结果。

备注:内容仅供参考。