首页 > 解决方案 > 如何使用 (Microsoft.AspNetCore.TestHost)TestServer 与客户端证书

问题描述

在 .net core api 中启用证书身份验证会导致 TestServer 在集成测试中始终返回 403-Forbidden(尽管请求中使用了证书)。

我尝试更改 TestClientProvider 中的 CertificateValidationService,但似乎证书验证在达到用户定义的身份验证逻辑之前失败了。在 Azure 中部署时,该服务与客户端证书一起正常工作。

我错过了什么吗?有没有办法将 TestServer 与受客户端证书保护的 API 一起使用?

重现

  1. 在 .NET Core API https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-3.1中启用证书身份验证
// Startup.cs
    ...
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<CertificateValidationService>();
        services.AddAuthentication(
            CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
        {
            ...
        });
        services.AddAuthorization();
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
    {
        ...

        app.UseRouting();

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

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
  1. 在您的 api 上使用“授权”属性
// WeatherForecastController.cs  (VS 2019 template)
    [ApiController]
    [Route("api/weather")]
    [Authorize]
    public class WeatherForecastController : ControllerBase
    {
    ...
    }
  1. 使用 Microsoft.AspNetCore.TestHost 编写集成测试
// IntegrationTests/ClientCertificateTests.cs
    [Fact]
    public async void GivenValidCertificate_PerformGet_ExpectSuccess()
    {
        X509Certificate2 validClientCertificate;
        using (var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
        {
            certStore.Open(OpenFlags.ReadOnly);
            validClientCertificate = certStore.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, true)[0];
        }

        using (var server = new TestClientProvider(ignoreCertificate: false).Server)
        {
            // Act
            var result = await server.SendAsync(context =>
            {
                context.Connection.ClientCertificate = validClientCertificate;
                context.Request.Method = "GET";
                context.Request.Path = "/api/weather";
            });

            // Assert
            Assert.Equal(200, result.Response.StatusCode);
        }
    }

标签: c#sslasp.net-coreintegration-testingasp.net-core-webapi

解决方案


根据https://github.com/dotnet/aspnetcore/issues/18177,我还必须将请求方案设置为“https”,这对我有用。

    var result = await server.SendAsync(context =>
    {
        context.Connection.ClientCertificate = validClientCertificate;
        context.Request.Method = "GET";
        context.Request.Scheme = "https";
        context.Request.Path = "/api/weather";
    });

推荐阅读