我有一个.netcore 3项目(WorkerService模板),该项目将JSON数据发送到REST端点。请求通过HttpClient发送,并配置为使用服务器所需的客户端证书。服务器响应始终为200和HTML字符。根据服务器管理者的说法,该请求被重定向到Web服务器的主页,因为客户端计算机已由特定用户正确处理,但没有证书可用。我正在使用以下代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("client").ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
X509Certificate2 certificate = GetCertificate(Configuration.CertificateSubjectKeyIdentifier);
handler.ClientCertificates.Add(certificate);
return handler;
}
}
GetCertificate从证书存储中检索证书:
private X509Certificate2 GetCertificate(string subjectIdentifier)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var collection = store.Certificates;
var certificates = collection.Find(X509FindType.FindBySubjectKeyIdentifier, subjectIdentifier, true);
foreach (var certificate in certificates)
{
if (DateTime.Compare(DateTime.Parse(certificate.GetExpirationDateString()), DateTime.Now) >= 0)
{
Logger.LogInformation($"Loaded X.509 certificate {certificate.Subject} issued by {certificate.Issuer}, valid from {certificate.GetEffectiveDateString()} to {certificate.GetExpirationDateString()}");
return certificate;
}
}
Logger.LogError($"X.509 certificate not loaded: No valid certificate could be found.");
return null;
}
发送请求的代码:
public async Task<ResponseData> PostAsync<T>(string url, T dataToSend)
{
ResponseData result = null;
HttpResponseMessage httpResponseMessage = null;
try
{
var errorHttp = false;
HttpClient httpClient;
using (httpClient = HttpClientFactory.CreateClient("client)) // IHttpClientFactory initialized in ctor
{
HttpContent httpContent;
using (httpContent = CreateJsonHttpContent(dataToSend, MediaType.ApplicationJson)) //build JSON from data
{
httpResponseMessage = await httpClient.PostAsync(url, httpContent).ConfigureAwait(false);
result = BuildResponseData(httpResponseMessage); //writes response data in a class
if (httpResponseMessage?.IsSuccessStatusCode == true)
{
result.Content = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
else
{
errorHttp = true;
}
if (errorHttp)
{
var httpRequestException = new HttpRequestException($"The http request to {url} was not successful.");
Logger.LogError($"{httpRequestException.Message} : {httpRequestException.InnerException}");
Logger.LogError(httpRequestException.StackTrace);
}
}
}
}
catch (SocketException socketException)
{
Logger.LogError($"{socketException.Message} : {socketException.InnerException}");
result = new ResponseData(socketException);
}
catch (WebException wex)
{
Logger.LogError($"{wex.Message} : {wex.InnerException}");
if (wex.Status == WebExceptionStatus.ConnectFailure || wex.Status == WebExceptionStatus.Timeout)
{
Logger.LogError($"Cannot connect to the rest service : {WebExceptionStatus.Timeout}");
}
}
catch (Exception ex)
{
LogException(ref ex);
result = new ResponseData(ex);
}
finally
{
httpResponseMessage?.Dispose();
}
return result;
}
使用PostAsync方法的类也已在ServiceCollection中注册。有什么想法在这里可能出什么问题吗?也可能是服务器端未正确处理证书吗?
我强烈怀疑客户端(您)端的配置错误。您的应用程序从LocalMachine
存储中读取证书。默认情况下,只有本地管理员和SYSTEM
帐户可以读取/使用私钥安装在LocalMachine
存储中的证书。
或者,将证书安装在运行客户端应用程序的用户帐户的CurrentUser
存储中,或显式授予私钥权限给运行客户端应用程序的用户帐户。为此:
LocalMachine
上下文中打开证书MMC管理单元(certlm.msc)Personal\Certificates
Manage Private Keys
菜单项。Read
权限。在这种情况下,您不需要修改代码或在商店之间移动证书。