Я использую последнюю версию .NET 8 HttpClient
для вызова конечной точки API.
Это мой код:
var cert = new X509Certificate("myCert.pfx", "mypass");
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual
};
handler.ClientCertificates.Add(cert);
using var httpClient = new HttpClient(handler);
var response = await httpClient.PostAsJsonAsync("https://<my-url>");
var resultString = await response.Content.ReadAsStringAsync();
Он сгенерировал следующее исключение:
System.Net.Http.HttpRequestException: An error occurred while sending the request.
---> System.IO.IOException: The decryption operation failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted.
--- End of inner exception stack trace ---
at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](Memory`1 buffer, CancellationToken cancellationToken)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at System.Net.Http.HttpConnection.InitialFillAsync(Boolean async)
at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
Кажется, это говорит о том, что закрытый ключ не работает должным образом. Я использовал тот же файл сертификата и пароль в Postman, и запрос был выполнен успешно и дал значимые результаты.
Вот некоторые из вещей, которые я пробовал:
Ничего из вышеперечисленного не помогло.
SocketsHttpHandler
(да, это сбивает с толку и непоследовательно документировано).
Ваш код смешивает типы, предназначенные для .NET Framework (4.x) и более старых версий .NET Core; якобы код, использующий их, должен работать без изменений в .NET 8, но программа не будет работать так хорошо, как могла бы - хотя на практике я обнаружил, что это приведет к ошибкам типа «Полученное сообщение было неожиданным или плохо отформатировано».
X509Certificate2
следует использовать вместо X509Certificate
(который восходит к .NET Framework 1.x в 2002 году; тогда как X509Certificate2
заменил его и был добавлен в .NET Framework 2.0 в 2005 году).
HttpClientHandler предназначен только для .NET Framework и .NET Core 1 + 2, а не для .NET 8 — вам следует использовать SocketsHttpHandler
. (да, это сбивает с толку и непоследовательно документировано).
HttpClientHandler
по-прежнему доступен в .NET 8, внутри это всего лишь оболочка SocketsHttpHandler
.Отмечу, что сообщенная вами ошибка 0x80090326 указывает на неспособность обеих сторон договориться об алгоритме набора шифров).
Я предлагаю вам изменить свой код на это и покрутить его:
X509Certificate2 clientCert = new X509Certificate2(
fileName: "myCert.pfx",
password: "mypass"
);
if ( !clientCert.HasPrivateKey ) throw new InvalidOperationException( "Private key not loaded." );
SocketsHttpHandler socksHandler = new SocketsHttpHandler
{
SslOptions =
{
// CipherSuitesPolicy = new CipherSuitesPolicy( ... ) // Only uncomment this if the underlying TLS error is due to a client/server disagreement over what TLS algos to use and this is the *only* way to resolve it.
ClientCertificates = new X509CertificateCollection()
{
clientCert
},
// SslProtocols = SslProtocols.Tls12 // Only uncomment this if you actually really need to specify exactly TLS 1.2. By default it will be negotiated.
}
};
using HttpClient httpClient = new HttpClient( socksHandler );
using HttpResponseMessage response = await httpClient.PostAsJsonAsync( "https://<my-url>", etc );
String responseBody = await response.Content.ReadAsStringAsync();
Вы устанавливаете корневой сертификат?