httpclient - 客户端证书获取“请求已中止:无法创建 SSL/TLS 安全通道”
问题描述
几年前,我努力让我们的代码包含客户端证书。(请参阅Elasticsearch NEST HttpClientHandler Certificate上的最后一篇文章)。我试图在另一个项目中使用相同的代码,但它失败了:
"ExceptionMessage": "The request was aborted: Could not create SSL/TLS secure channel."
大多数建议都围绕设置 ServicePointManager.SecurityProtocol = Tls12; 我已经尝试了所有的组合。
我试图缩小范围并简单地添加
直接使用 HttpClientHandler
来自https://damienbod.com/2019/09/07/using-certificate-authentication-with-ihttpclientfactory-and-httpclient/的示例
private async Task<JsonDocument> GetApiDataUsingHttpClientHandler()
{
var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(cert);
var client = new HttpClient(handler);
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44379/api/values"),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var data = JsonDocument.Parse(responseContent);
return data;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
}
这在一个方法中完成了整个事情(读取证书、附加到处理程序并发出请求)。如果我在独立项目中运行此代码,它工作正常。我正在尝试从 Service Fabric 中托管的 WebApi 运行它。调试时,可以看到证书已获取并正确添加到处理程序中。正如 Fiddler 所验证的那样,该调用永远不会从我的代码中消失(即从未发出过)。
我们正在另一个解决方案中的 Service Fabric 中执行此操作,并且一切正常。
还有其他东西可能会丢失吗?
谢谢!
PS添加完整的例外
{
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred while sending the request.",
"ExceptionType": "System.Net.Http.HttpRequestException",
"StackTrace": " at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Net.Http.HttpClient.<FinishSendAsyncBuffered>d__58.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "The request was aborted: Could not create SSL/TLS secure channel.",
"ExceptionType": "System.Net.WebException",
"StackTrace": " at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)"
}
}
解决方案
通过比较我们的两个解决方案,我发现了一些可以解决的问题。我不知道这实际上是在做什么伏都教,但它确实有效。我认为它需要某种用户上下文来打开频道。
在 Service Fabric 项目的 AppManifest.xml 中,我在底部添加了以下内容:
<Principals>
<Users>
<User Name="SomeUserName">
<MemberOf>
<SystemGroup Name="Administrators" />
</MemberOf>
</User>
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="SomeUserName" />
</Policies>
请注意,“SomeUserName”实际上并不对应于我系统上的任何用户帐户。也许它正在内存中创建用户上下文。
推荐阅读
- javascript - 是否可以动态更改 manifest.json 文件
- opengl - 如何将视图从 OpenGL 提取到视频流?
- c# - 随机错误 内存流不可扩展
- java - 是否有用于检查代码中注释存在的 Maven 插件?
- c# - Api 在提琴手中返回结果,但响应不是控制台中的结果
- flutter - Flutter navigator 2.0 强制创建新状态
- javascript - 使用 cypress 获取数组的索引会返回“-1”
- php - PHP关闭每个循环中的html标签
- python - 在套接字服务器中运行 Kivy 应用程序时出现黑屏
- windows - 在powershell脚本中连续读取串口数据