测试环境下自定义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); }
关键修正点
- 重新配置认证服务:通过
AddAuthentication+AddJwtBearer完全覆盖原有认证配置,而非直接注册Options实例 - 移除冲突服务:清除已注册的认证相关服务,确保新配置完全生效
- 改用
async Task:替换async void,让xUnit能正确等待异步操作完成
内容的提问来源于stack exchange,提问作者Complexity
相关产品推荐
相关产品推荐

