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

测试环境下自定义JWT验证配置无效问题排查

问题:ASP.NET Core测试环境中JWT验证失败,生产环境配置相同却正常

原应用认证/授权配置

services.AddAuthorization(
    static options => options.AddPolicy(
        "Bearer", new AuthorizationPolicyBuilder()
                  .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                  .RequireAuthenticatedUser()
                  .Build()));

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => {
            options.Authority = identityProviderEndpoint;

            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = identityProviderEndpoint,
                ValidAudience = applicationAudience,
                RequireSignedTokens = true,
            };
        });

该配置可正常验证Auth0颁发的Token。

测试用例代码

为了测试,我编写了禁用所有JWT校验的测试用例:

[Fact(DisplayName = "HTTP Forbidden: Requesting (Valid JWT) an authorized endpoint (JWT Validation disabled).")]
internal async void RequestingAnEndpointThatRequiresAuthorizationWithAValidJWT()
{
    // ARRANGE.
    HttpClient httpClient = this.webApplicationFactory.WithWebHostBuilder(
                                    builder =>
                                    {
                                        builder.ConfigureTestServices(
                                            services =>
                                            {
                                                var options = new JwtBearerOptions();

                                                options.TokenValidationParameters = new TokenValidationParameters
                                                {
#pragma warning disable CA5404 // "Do not disable token validation checks" - By design.      
                                                    ValidateIssuer = false,
                                                    ValidateAudience = false,  
                                                    ValidateLifetime = false,
#pragma warning restore CA5404
                                                    ValidateIssuerSigningKey = false,
                                                    RequireSignedTokens = false,
                                                    IssuerSigningKey = new SymmetricSecurityKey(
                                                        Encoding.UTF8.GetBytes("UTrust.S1gn1ngK3Y!")),
                                                };

                                                services.AddSingleton(options);
                                            });
                                    })
                                .CreateClient();

    httpClient.DefaultRequestHeaders.Add(
        "Authorization",
        "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.T7sFpO0XoaJ9JWsu2J1ormK99zs4zIr2s25jjl8RVSw");

    // ACT.
    HttpResponseMessage result = await httpClient.GetAsync("/authorized")
                                                 .ConfigureAwait(false);

    // ASSERT.
    result.Should()
          .HaveStatusCode(HttpStatusCode.OK);
}

问题现象

传入的JWT可正常通过JWT校验工具验证,但测试返回Unauthorized状态码;而将相同的禁用校验配置放到实际应用中,用curl请求可返回200 OK。请问测试中遗漏了什么?


问题原因与解决方案

核心问题

测试中直接注册JwtBearerOptions单例不会覆盖原有认证配置:ASP.NET Core的认证系统依赖IOptions<JwtBearerOptions>读取配置,而非直接的JwtBearerOptions实例。原测试中的AddSingleton(options)无法覆盖AddJwtBearer内部注册的配置提供者,导致实际生效的还是生产环境的校验规则。

另外,测试方法使用async void会导致xUnit无法正确跟踪异步操作完成,也可能引发不可预期的结果。

修正后的测试代码

[Fact(DisplayName = "HTTP OK: 使用禁用校验的JWT请求授权端点")]
internal async Task RequestingAnEndpointThatRequiresAuthorizationWithAValidJWT()
{
    // ARRANGE.
    HttpClient httpClient = this.webApplicationFactory.WithWebHostBuilder(
                                    builder =>
                                    {
                                        builder.ConfigureTestServices(
                                            services =>
                                            {
                                                // 移除原有认证相关服务,避免配置冲突
                                                services.RemoveAll<IAuthenticationSchemeProvider>();
                                                services.RemoveAll<IPostConfigureOptions<JwtBearerOptions>>();

                                                // 重新配置认证,覆盖原有规则
                                                services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                                                        .AddJwtBearer(options =>
                                                        {
                                                            options.TokenValidationParameters = new TokenValidationParameters
                                                            {
#pragma warning disable CA5404 // 测试场景故意禁用校验
                                                                ValidateIssuer = false,
                                                                ValidateAudience = false,
                                                                ValidateLifetime = false,
#pragma warning restore CA5404
                                                                ValidateIssuerSigningKey = false,
                                                                RequireSignedTokens = false,
                                                            };
                                                        });
                                            });
                                    })
                                .CreateClient();

    httpClient.DefaultRequestHeaders.Add(
        "Authorization",
        "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.T7sFpO0XoaJ9JWsu2J1ormK99zs4zIr2s25jjl8RVSw");

    // ACT.
    HttpResponseMessage result = await httpClient.GetAsync("/authorized")
                                                 .ConfigureAwait(false);

    // ASSERT.
    result.Should()
          .HaveStatusCode(HttpStatusCode.OK);
}

关键修正点

  1. 重新配置认证服务:通过AddAuthentication+AddJwtBearer完全覆盖原有认证配置,而非直接注册Options实例
  2. 移除冲突服务:清除已注册的认证相关服务,确保新配置完全生效
  3. 改用async Task:替换async void,让xUnit能正确等待异步操作完成

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 01:10:25