我有一个.NET Core 3.1的C#应用程序,通过HTTPS调用API(并在获取令牌时呈现其公钥,因为该证书稍后用于解密单独发送的信息)。 在我们几乎所有的机器上都可以正常工作,但是在一个Windows 8.1机器上,当我们尝试最初连接进行身份验证令牌时,我们会收到以下一系列异常:
The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted.
异常是从System.Net.Http.HttpClient.FinishSendAsyncBuffered
抛出的,所以我怀疑它发生在HTTPS层面上,我们的证书内容在这里并不相关。
我们获取令牌的代码如下:
认证服务的构造函数:
public XXXXAuthService(IXXDbService dbService, XXXXApiConfig config)
{
_dbService = dbService;
_config = config;
// try forcing TLS1.2 for SSL connection exceptions thrown in some operating environments
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
_httpClient = new HttpClient {BaseAddress = new Uri(config.BaseUrl)};
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
获取授权令牌的代码:
private async Task<string> GetXXXXBearerToken(string userId, DateTime creationTime)
{
var token = await GenerateProviderJwtForXXXX(userId, creationTime);
var kvp = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange"),
new KeyValuePair<string, string>("subject_token", token),
new KeyValuePair<string, string>("subject_token_type", "urn:ietf:params:oauth:token-type:jwt")
};
var data = new FormUrlEncodedContent(kvp);
var publicKey = await GetXXXXPublicKey();
_httpClient.DefaultRequestHeaders.Remove("X-XXXX-Public-Cert");
_httpClient.DefaultRequestHeaders.Add("X-XXXX-Public-Cert", publicKey);
var response = await _httpClient.PostAsync("Identity/token", data);
if (!response.IsSuccessStatusCode)
throw new Exception("XXXX Token Server Error: " + response.ReasonPhrase);
var result = await response.Content.ReadAsStringAsync();
var authResponse = JsonConvert.DeserializeObject<OAuthResponse>(result);
if (!string.IsNullOrEmpty(authResponse.access_token))
return authResponse.access_token;
System.Diagnostics.Trace.WriteLine("Token Exchange Result: " + result);
if (!string.IsNullOrEmpty(authResponse.error))
{
var outcome = new XXX.XXXX.Model.OperationOutcome();
outcome.Issue.Add(new XXX.XXXX.Model.OperationOutcome.IssueComponent()
{
//some code to throw an error is here
}
throw new XXX.XXXX.Rest.XXXXOperationException("Bearer Token Exchange failed", response.StatusCode);
}
很不幸,Stack Overflow或者其他网站上关于这个特定错误的现有问题/建议似乎都没能帮到我。它们主要涉及客户端和服务器之间的版本差异,但在这里似乎并非如此,因为我正在强制使用TLS 1.2(该协议在失败的机器上已经激活和启用)。
有趣的是,我可以通过HTTPS在浏览器中完全访问服务器URL,这表明我的代码存在问题,而不是机器,但在其他地方它可以正常工作。
我确认:
- 我在机器上使用来验证连接的证书是有效的,并且具有信任链(尽管如上所述,我们似乎没有达到TLS连接本身失败的那一步)
- 我们调用的服务器支持TLS 1.2(通过强制使用它)
- 我可以独立通过浏览器访问URL的网站
是否需要在代码或机器上执行某些操作才能在各处使此调用正常工作?
我尝试过的解决方法
- 安装所有Windows 8.1更新到现在
- 在代码中强制使用TLS 1.2(请参见上面的代码示例)
- 将VM限制为仅使用TLS 1.2
System.ComponentModel.Win32Exception(0x80090326):接收到的消息意外或格式不正确
。 Wireshark确实指出了握手问题。 - Anton Krouglov