3
votes

Comment configurer le certificat avec httpClientFactory

J'utilise httpClientFactory pour demander une API Wechat Pay, mais l'API Wechat Pay a besoin d'un certificat. Comment puis-je configurer httpClientFactory pour utiliser le certificat?


0 commentaires

3 Réponses :


2
votes

Tout d'abord, vous devez vous enregistrer 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
        }
    }
}

Dans l'exemple, le fichier foo.pfx contient un certificat avec le mot de passe 123 . ** signé * est le nom de HttpClient.

Deuxièmement, vous appellerez IHttpClientFactory.CreateClient pour créer le HttpClient code > instance.

public class PayClient
{
    private readonly IHttpClientFactory _httpClientFactory;

    public PayClient(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public async Task SomePayMethodAsync()
    {
        using (httpClient = _httpClientFactory.CreateClient("signed"))
        {
            // use httpClient
        }
    }
}

Vous devez utiliser le même nom signé que le paramètre de CreateClient .

MISE À JOUR PLUS TARD

Si vous écrivez SAAS avec de nombreux certificats, vous pouvez créer et configurer manuellement un HttpClient chaque fois que vous en avez besoin. C'est le moyen le plus simple.

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);
        });


9 commentaires

Mais, comment configurer différents cert avec la même URL d'API. parce que j'ai beaucoup de comptes différents et de certificats différents pour demander une même URL d'API.


@ junlei.lv Vous pouvez enregistrer quelques clients avec des noms différents. Chaque classe comme PayClient peut créer son propre HttpClient . Habituellement, vous avez un certificat unique pour certains services distants, cette décision devrait donc fonctionner.


Merci beaucoup.Mais cette méthode ne peut pas résoudre ma question.parce que mon logiciel est une plate-forme saas.nous avons beaucoup de clients.Chaque client a un certificat différent.Mais l'adresse de l'api payante est la même.So.enregistrez quelques clients avec des noms différents. pas très bon.


avez-vous un autre moyen?


@ junlei.lv J'ai mis à jour ma réponse avec la solution alternative. Peut-être que cela vous convient mieux.


en fait, j'utilise cette méthode maintenant. mais cette méthode créera de nombreux tcp time_wait


pouvons-nous parler de cette question par e-mail?


@ junlei.lv Si vous souhaitez optimiser le code, vous pouvez mettre en cache les instances HttpClientHandler . En tant que base, vous pouvez obtenir l'implémentation de la classe DefaultHttpClientFactory ici .


L'approche de «mise à jour ultérieure» ne conduira-t-elle pas à l'épuisement des ports?



2
votes

Si vous regardez la fabrique par défaut retournée dans DI, elle hérite de deux interfaces, et lors de l'injection vous avez choisi de n'en utiliser qu'une:

classe interne DefaultHttpClientFactory: IHttpClientFactory, IHttpMessageHandlerFactory p >

Sachant cela, vous pouvez prendre une solution de contournement sournoise:

_handlerFactory = _clientFactory as IHttpMessageHandlerFactory;

Maintenant, si vous regardez l'usine de gestionnaires, il a une méthode CreateHandler avec le même argument de chaîne que la méthode CreateClient . En fait, si vous regardez l'implémentation de CreateClient , vous pouvez voir qu'il utilise cette méthode qui met ensuite en cache le gestionnaire.

Alors oubliez Startup: Cast votre usine client en usine de gestionnaire, créez un gestionnaire pour votre utilisateur spécifique, vérifiez toutes les propriétés du gestionnaire (comme le certificat ou devez-vous l'ajouter puisqu'il s'agit d'une nouvelle instance), puis appelez CreateClient comme d'habitude. p >

Modifier: Au démarrage, vous devrez peut-être encore ajouter ConfigurePrimaryHttpMessageHandler pour créer réellement un HttpClientHandler, vous devrez donc peut-être faire une consession en n'enregistrant qu'un seul nommé HttpClient et en échangeant simplement le certificat. Cela vous donne quand même les avantages d'avoir l'usine.

Edit 2: sachez que le gestionnaire est emballé un tas de fois dans les décorateurs, vous devez donc creuser profondément. L'astuce que j'utilise est:

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


2 commentaires

C'est bien! J'utilise.NET Core 3.1 main ayant des problèmes et je pense que cela le résout. J'essaye d'échanger le certificat par demande (semblable à l'OP). Pouvez-vous nous expliquer à quoi ressemblerait la startup? Cela m'aiderait tellement!


J'ai ajouté des services.AddHttpClient (); mais quand j'ai utilisé le DI IHttpMEssageHandlerFactory, il est nul. Un conseil s'il vous plait? Merci



-1
votes

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

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


0 commentaires