Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# HttpClient与客户端证书一起重用_C#_.net_Asp.net Web Api_Dotnet Httpclient - Fatal编程技术网

C# HttpClient与客户端证书一起重用

C# HttpClient与客户端证书一起重用,c#,.net,asp.net-web-api,dotnet-httpclient,C#,.net,Asp.net Web Api,Dotnet Httpclient,我在几个地方(比如,或者)读到过,在请求之后直接处理HttpClient是一种不好的做法,最好在所有请求发出之后处理它,以允许重新使用连接 为了进行尝试,我创建了一个HttpClient实例,并通过以下方式将其添加到类中的静态字段中: public class Test { private static X509Certificate2 _certificate; private static HttpClient HttpClient { get; set; } ..

我在几个地方(比如,或者)读到过,在请求之后直接处理HttpClient是一种不好的做法,最好在所有请求发出之后处理它,以允许重新使用连接

为了进行尝试,我创建了一个HttpClient实例,并通过以下方式将其添加到类中的静态字段中:

public class Test
{
    private static X509Certificate2 _certificate;
    private static HttpClient HttpClient { get; set; }

    ...

    public Test()
    {
        ...

        if (HttpClient == null)
        {
            LoadCertificate();

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                                                    | SecurityProtocolType.Tls11
                                                    | SecurityProtocolType.Tls12
                                                    | SecurityProtocolType.Ssl3;

            var handler = new WebRequestHandler();
            handler.ClientCertificates.Add(_certificate);
            HttpClient = new HttpClient(handler, false);
        }
    }

    private void LoadCertificate()
    {
        using (var store = new X509Store(StoreName.My, CertificateStoreLocation))
        {
            store.Open(OpenFlags.ReadOnly);
            var certificates = store.Certificates.Find(X509FindType.FindBySubjectName, CertificateFriendlyName, true);
            if (certificates.Count != 1)
                throw new ArgumentException(
                    $"Cannot find a valid certificate with name {CertificateFriendlyName} in {CertificateStoreLocation}");
            _certificate = certificates[0];

            store.Close();
        }

        ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    }

}
然后,我使用实例通过以下命令调用web服务:

var result = await HttpClient.PostAsJsonAsync(completeUri, request);
第一次运行代码时,一切正常,我得到了正确的响应,但随后,我从服务器收到一个未经授权的消息,告诉我没有使用客户端证书


就好像对于以下调用,没有考虑
WebRequestHandler

您的修复程序应该如下所示:

handler.PreAuthenticate = true;

一旦建立了与服务的连接,就可以使用具有不同身份验证信息的不同客户端重新使用它与之通信。这意味着,服务需要知道每次哪个客户端发送了一个请求,否则它可能是一个安全漏洞-例如,在最后连接的客户端下执行一个请求。这取决于您的身份验证机制,但基本上
WebRequestHandler
在第一个请求后设置标志
IsAuthenticated
,并在下一个请求中停止发送身份验证信息。
PreAuthenticate
选项强制在每次请求时发送验证信息。

关于处理HttpClient-这并不完全正确。连接管理由
ServicePointManager
完成,但不是直接由HttpClient(它使用HttpClientHandler,它在引擎盖下使用WebRequest)完成。因此,如果您有一个保持TCP连接活动的设置,或者您有多个对同一
服务点
的请求同时运行,HttpClient的处理将不会关闭基础连接。是的,这就是我的意思。处理HttpClient将使连接保持活动状态,而将其放入using()被认为是不好的做法,因为这将创建大量保持打开状态的连接。这是我链接的帖子和网站所解释的。这似乎并没有解决它,我仍然有同样的行为,在第一次请求时工作正常,但在所有后续操作中都失败了。没关系,事实上就是这样。我认为它仍然不起作用,但这是另一个完全无关的问题。请将您的答案标记为正确,谢谢。