【问题标题】:How to config certificate with httpClientFactory如何使用 httpClientFactory 配置证书
【发布时间】:2019-06-30 01:41:27
【问题描述】:

我正在使用httpClientFactory申请微信支付API,但是微信支付API需要证书。如何配置httpClientFactory 使用证书?

【问题讨论】:

    标签: asp.net-core


    【解决方案1】:

    如果您查看 DI 中返回的 Default factory,它继承自两个接口,并且在注入时您选择只使用一个:

    internal class DefaultHttpClientFactory : IHttpClientFactory, IHttpMessageHandlerFactory

    知道了这一点,您可以采取一种偷偷摸摸的解决方法:

    _handlerFactory = _clientFactory as IHttpMessageHandlerFactory;

    现在,如果您查看处理程序工厂,它有一个方法CreateHandler,其字符串参数与CreateClient 方法相同。实际上,如果你查看CreateClient 的实现,你会发现它使用了这个方法,然后缓存了处理程序。

    所以忘记启动:将您的客户端工厂转换为处理程序工厂,为您的特定用户创建处理程序,验证处理程序上的所有属性(比如那里的证书或者您是否需要添加它,因为它是一个新实例)和然后像往常一样拨打CreateClient

    编辑:在启动时,您可能仍需要添加 ConfigurePrimaryHttpMessageHandler 以实际创建一个 HttpClientHandler,因此您可能必须只注册一个名为 HttpClient 并交换证书。尽管如此,它仍然为您提供了拥有工厂的优势。

    编辑2:知道处理程序在装饰器中被包裹了很多次,所以你需要深入挖掘。我使用的技巧是:

    var handler = _handlerFactory.CreateHandler("customer");
    while (handler as DelegatingHandler != null)
    {
       handler = (handler as DelegatingHandler).InnerHandler;
    }
    var clientHandler = handler as HttpClientHandler;
    

    【讨论】:

    • 这太棒了!我正在使用.NET Core 3.1 手有问题,我认为这解决了它。我正在尝试根据请求交换证书(类似于 OP)。能否请您详细介绍一下 Startup 的样子?这对我有很大帮助!
    • 我添加了 services.AddHttpClient();但是当我使用 DI IHttpMEssageHandlerFactory 时,它为空。请问有什么建议吗?谢谢
    • HttpMessageHandler 将被池化直到过期时间(默认 2 分钟),所以在请求完成之前更改处理程序属性不会造成任何问题?
    【解决方案2】:

    首先,您需要注册HttpClient

    services.AddHttpClient("signed")
            .ConfigurePrimaryMessageHandler(() =>
            {
                var handler = new HttpClientHandler();
                var certificate = new X509Certificate2(filename: "foo.pfx", password: "123");
    
                handler.ClientCertificateOptions = ClientCertificateOptions.Manual;
                handler.ClientCertificates.Add(certificat);
            });
    

    在示例中,文件 foo.pfx 包含密码为 123 的证书。 签名HttpClient的名称。

    其次,您将调用IHttpClientFactory.CreateClient 来创建HttpClient 实例。

    public class PayClient
    {
        private readonly IHttpClientFactory _httpClientFactory;
    
        public PayClient(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }
    
        public async Task SomePayMethodAsync()
        {
            using (httpClient = _httpClientFactory.CreateClient("signed"))
            {
                // use httpClient
            }
        }
    }
    

    您需要使用与CreateClient的参数相同的名称签名

    稍后更新

    如果您使用许多证书编写 SAAS,您可以在每次需要时手动创建和配置 HttpClient。这是最简单的方法。

    public class PayClient
    {
        private readonly ICurrentUserProvider _currentUserProvider;
    
        public PayClient(ICurrentUserProvider _currentUserProvider)
        {
            _currentUserProvider = currentUserProvider;
        }
    
        private HttpClient CreateHttpClient()
        {
            var currentUser = _currentUserProvider.CurrentUser;
            var filename = currentUser.CertificateFilename;
            var password = currentUser.CertificatePassword;
            var handler = new HttpClientHandler();
            var certificate = new X509Certificate2(filename, password);
    
            handler.ClientCertificateOptions = ClientCertificateOptions.Manual;
            handler.ClientCertificates.Add(certificat);
    
            return new HttpClient(handler);
        }
    
        public async Task SomePayMethodAsync()
        {
            using (httpClient = CreateHttpClient())
            {
                // use httpClient
            }
        }
    }
    

    【讨论】:

    • 但是,如何使用相同的 api url 配置不同的证书。因为我有许多不同的帐户和不同的证书来请求相同的 api url。
    • @junlei.lv 你可以注册几个不同名字的客户端。像PayClient 这样的每个类都可以创建自己的HttpClient。通常你有一些远程服务的单一证书,所以这个决定应该有效。
    • 非常感谢。但是这个方法不能解决我的问题。因为我的软件是一个saas平台。我们有很多客户端。每个客户端都有不同的证书。但是支付api地址是一样的。所以。注册几个不同名字的客户不是很好。
    • 你还有什么办法吗?
    • “稍后更新”方法不会导致端口耗尽吗?
    【解决方案3】:

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1

    services.AddHttpClient("configured-disable-automatic-cookies")
        .ConfigurePrimaryHttpMessageHandler(() =>
        {
            return new SocketsHttpHandler()
            {
                UseCookies = false,
            };
        });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-24
      • 1970-01-01
      • 2011-10-19
      • 1970-01-01
      • 1970-01-01
      • 2020-06-07
      • 2010-09-25
      相关资源
      最近更新 更多