【问题标题】:How send different client certificates on different requests with a single instance of HttpClient in .Net Core?如何在 .Net Core 中使用单个 HttpClient 实例针对不同请求发送不同的客户端证书?
【发布时间】:2019-12-18 15:07:06
【问题描述】:

HttpClient 的推荐是reuse a single instance。但从 API 看来,添加证书的方式似乎是在实例上,而不是每个请求。如果我们添加两个证书,我们如何确保“cert 1”只发送到“one.somedomain.com”?

//A handler is how you add client certs (is there any other way?)
var _clientHandler = new HttpClientHandler();

//Add multiple certs
_clientHandler.ClientCertificates.Add(cert1);
_clientHandler.ClientCertificates.Add(cert2);
_clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;


//Pretend this is our long-living HttpClient
var client = new HttpClient(_clientHandler);

//Now if we make a post request, will both certs be used?
using (HttpResponseMessage response = _client.PostAsync("https://one.somedomain.com", content).Result)
{
    //...elided...
 }

【问题讨论】:

  • 看来,您需要以可取的行为实现自己的HttpClientHandler
  • 我认为为每台服务器创建新的 HttpClient 可以节省一天的时间。您可以将它们放在字典中,其中键是服务器基地址
  • @KrivitskiyGrigoriy 这可能是唯一的选择,但我想知道这是否会在每个请求上增加太多额外的处理,或者是否有办法保持快速?另外,你知道怎么做吗?

标签: c# .net asp.net-core .net-core dotnet-httpclient


【解决方案1】:

对不起。年底工作量大。 你可以尝试实现这样的东西:

public class CustomHttpHandler : HttpClientHandler
{
    private readonly Dictionary<string, X509Certificate> _certMap;

    public CustomHttpHandler():base()
    {
        _certMap = new Dictionary<string, X509Certificate>() { { "server1name", new X509Certificate("cert1") }, { "server2name", new X509Certificate("cert2") } };
    }

    protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
    {
        string serverName = request.RequestUri.Host;
        if (ClientCertificates.Contains(_certMap[serverName]))
        {
            try
            {
                var response = await base.SendAsync(request, cancellationToken);
                return response;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                throw;
            }
        }
        else
        {
            ClientCertificates.Clear();
            ClientCertificates.Add(_certMap[serverName]);

            try
            {
                var response = await base.SendAsync(request, cancellationToken);
                return response;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                throw;
            }
        }
    }
}

只是一个想法,没有经过测试。 或者,您也可以在 RequestMessage 实例中使用 Headers 集合。 本文涵盖主题:https://damienbod.com/2019/09/07/using-certificate-authentication-with-ihttpclientfactory-and-httpclient/

【讨论】:

  • 有什么办法可以在退出前处理 Dictionary 的值。
【解决方案2】:

这是建议,但是,您可以使用“使用”语句。

一旦 HttpClient 是 IDisposable,你应该使用类似的东西

using(var client = new HttpClient(_clientHandler))
{
    //Your code here
}

【讨论】:

  • 这不是微软特别推荐的,会引入性能问题、内存泄漏和连接句柄泄漏
猜你喜欢
  • 2017-12-04
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2022-07-01
相关资源
最近更新 更多