.net 核心中的 HttpClientHandler 不包含客户端证书

Client certificate not included by HttpClientHandler in .net core

我在使用 HttpClientHandler 发送证书时遇到困难,因为证书根本不会出现在服务器的请求中。该证书具有用于服务器和客户端身份验证的正确 EKU,以及“数字签名”的密钥使用。 @davidsh 认为问题 26531 是因为 HttpClient 缺少日志记录,但是 运行 我在 Visual Studio 中的项目(日志设置为 Trace 并使用 dotnet 3.1.401)没有输出错误.我对 logman 不是很熟悉,但我 运行 当我执行我的代码时应该发生问题并且日志中没有任何内容表明可能是什么问题时,我会使用它。 运行 没有测试代码的选项 我试图在客户端请求中添加一个没有私钥的证书,以查看 httpClientHandler.ClientCertificates.Add ... 是否会抛出任何错误,比如“你需要一个带有私钥的证书签署你的请求”,它不应该说什么吗?

在客户端:

services.AddHttpClient<ILetterManClient, LetterManClient.LetterManClient>()
    .ConfigureHttpClient(client =>
    {
        client.BaseAddress = new Uri(configuration.GetValue<string>("Microservices:LetterManAPI"));
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        HttpClientHandler httpClientHandler = new HttpClientHandler();

        httpClientHandler.ServerCertificateCustomValidationCallback = ValidateServiceCertficate;
        httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;

        clientCertificate = new X509Certificate2("client_cert.pfx", "developer");

        httpClientHandler.ClientCertificates.Add(clientCertificate);

        return httpClientHandler;
    });

在服务器上:

public class ValidateClientCertificates : TypeFilterAttribute
{
    public ValidateClientCertificates() : base(typeof(ValidateClientCertificatesImpl))
    {

    }

    private class ValidateClientCertificatesImpl : IAsyncAuthorizationFilter
    {
        X509Certificate2 clientCertificate;
        public ValidateClientCertificatesImpl(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
        {
            clientCertificate = new X509Certificate2("client_cert.crt");
        }

        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var certificate = await context.HttpContext.Connection.GetClientCertificateAsync();

            if ((certificate == null) || (!certificate.Thumbprint.Equals(clientCertificate.Thumbprint)))
            {
                context.Result = new UnauthorizedObjectResult("");
                return;
            }
        }
    }
}

旁注: 我也一直在尝试使用从 corefx 存储库编译的代码来调试我的项目,以查看发生了什么,但是 Visual Studio 坚持引用本地安装的 sdk 中的代码,而不是引用它的 corefx 中的项目,但这是另一个问题。

我创建了 this project 来模拟这个问题。它创建证书,它有两个项目,一个服务和另一个客户端实现。

非常欢迎任何帮助。

These 是 Kestrel 要求客户端证书的准则,但它假设计算机中安装了 CA,否则您必须在配置 Kestrel 服务器时直接指定客户端证书,如下所示:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
            webBuilder.ConfigureKestrel(o =>
            {
                o.ConfigureHttpsDefaults(o => {
                    o.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
                    o.ClientCertificateValidation = ValidateClientCertficate;
                });
            });
        });

public static Func<X509Certificate, X509Chain, SslPolicyErrors, bool> ValidateClientCertficate =
    delegate (X509Certificate serviceCertificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        X509Certificate2 clientCertificate;
        clientCertificate = new X509Certificate2("client.crt");

        if (serviceCertificate.GetCertHashString().Equals(clientCertificate.Thumbprint))
        {
            return true;
        }

        return false;
    };

不幸的是,您不能像我预期的那样要求特定路由的客户端证书。