HTTPClient 在成功之前获得两个 401(发送错误的令牌)
HTTPClient getting two 401s before success (sending wrong token)
我正在尝试使用 HttpClient
与自托管 WebAPI 客户端通信。使用以下代码创建客户端:
HttpClientHandler clientHandler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
var client = new HttpClient(clientHandler);
在服务器端我们设置:
HttpListener listener = (HttpListener)app.Properties[typeof(HttpListener).FullName];
listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
在 Startup
文件中。
问题是在处理请求之前,我收到 两个 (或预身份验证后的一个)401 错误。
在 fiddler 中,序列如下所示:
First request:
Authorization: Negotiate TlRMTVNTUAABAAAAl7II4gcABwAxAAAACQAJACgAAAAGAbEdAAAAD1dTMTEzLTEyMFNXVC0xMTM=
Answer:
WWW-Authenticate: Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVwonisrQOBMTKHhKwCkgCAAAAAJoAmgBGAAAABgGxHQAAAA9TAFcAVAAtADEAMQAzAAIADgBTAFcAVAAtADEAMQAzAAEAEgBXAFMAMQAxADMALQAxADIAMAAEABYAcwB3AHQALQAxADEAMwAuAGwAbwBjAAMAKgBXAFMAMQAxADMALQAxADIAMAAuAHMAdwB0AC0AMQAxADMALgBsAG8AYwAFABYAQQBMAEQASQA5ADkAOQAuAGwAbwBjAAcACACkGh0XVY3QAQAAAAA=
Second request (succeeds):
Authorization: Negotiate TlRMTVNTUAADAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAFcKI4gYBsR0AAAAPfJafWSuLL0sAXYtWCynOqg==
那么,为什么我的客户端不是第一次发送正确的授权令牌,而是总是需要这种两次方法?
仅在收到 HTTP 401 未授权响应后才发送凭据的默认行为。
手动添加凭据header 似乎是可用的最佳解决方案。
您遇到的是正常现象,这就是 NTLM 身份验证方案的工作原理。
1: C --> S GET ...
2: C <-- S 401 Unauthorized
WWW-Authenticate: NTLM
3: C --> S GET ...
Authorization: NTLM <base64-encoded type-1-message>
4: C <-- S 401 Unauthorized
WWW-Authenticate: NTLM <base64-encoded type-2-message>
5: C --> S GET ...
Authorization: NTLM <base64-encoded type-3-message>
6: C <-- S 200 Ok
- 客户端向服务器发送
GET
请求。
- 由于您需要通过身份验证才能访问请求的资源,因此服务器会发回
401 Unathorized
响应并在 WWW-Authenticate
header 中通知客户端它支持 NTLM
认证。所以这是您获得第一个 401
响应代码的地方。
- 客户端在
Authorization
header中向服务器发送域名和用户名。请注意,仅基于这些信息还不能对客户端进行身份验证。
- 服务器向客户端发送质询。这是一个随机生成的数字,称为 nonce。这是您获得第二个
401
响应代码的地方。
- 客户端发回对服务器质询的响应,使用其密码的散列来加密随机数。
- 服务器将客户端的用户名、发送给客户端的质询以及从客户端收到的响应发送给域控制器。使用用户名,域控制器检索用户密码的哈希值并用它加密质询。如果结果与客户端发送的响应匹配,则客户端通过身份验证,服务器向客户端发回
200
响应代码和请求的资源。
遇到了类似的问题,经过大量回答后,none 的答案有效。以下工作正常,但没有出现两个 401:
var credential = new NetworkCredential("username", "password", "domainname");
var myCache = new CredentialCache();
// Add the target Uri to the CredentialCache with credential object
myCache.Add(new Uri("http://targeturi/"), "NTLM", credential);
// Create an HttpClientHandler to add some settings
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = true;
handler.Credentials = myCache;
// Create an HttpClient with the handler object
httpClient = new HttpClient(handler);
// Wait to get the reponse, and you can use the reponse in your code
HttpResponseMessage response = await httpClient.GetAsync(resourceUri);
我正在尝试使用 HttpClient
与自托管 WebAPI 客户端通信。使用以下代码创建客户端:
HttpClientHandler clientHandler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
var client = new HttpClient(clientHandler);
在服务器端我们设置:
HttpListener listener = (HttpListener)app.Properties[typeof(HttpListener).FullName];
listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
在 Startup
文件中。
问题是在处理请求之前,我收到 两个 (或预身份验证后的一个)401 错误。
在 fiddler 中,序列如下所示:
First request:
Authorization: Negotiate TlRMTVNTUAABAAAAl7II4gcABwAxAAAACQAJACgAAAAGAbEdAAAAD1dTMTEzLTEyMFNXVC0xMTM=
Answer:
WWW-Authenticate: Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVwonisrQOBMTKHhKwCkgCAAAAAJoAmgBGAAAABgGxHQAAAA9TAFcAVAAtADEAMQAzAAIADgBTAFcAVAAtADEAMQAzAAEAEgBXAFMAMQAxADMALQAxADIAMAAEABYAcwB3AHQALQAxADEAMwAuAGwAbwBjAAMAKgBXAFMAMQAxADMALQAxADIAMAAuAHMAdwB0AC0AMQAxADMALgBsAG8AYwAFABYAQQBMAEQASQA5ADkAOQAuAGwAbwBjAAcACACkGh0XVY3QAQAAAAA=
Second request (succeeds):
Authorization: Negotiate TlRMTVNTUAADAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAFcKI4gYBsR0AAAAPfJafWSuLL0sAXYtWCynOqg==
那么,为什么我的客户端不是第一次发送正确的授权令牌,而是总是需要这种两次方法?
仅在收到 HTTP 401 未授权响应后才发送凭据的默认行为。
手动添加凭据header 似乎是可用的最佳解决方案。
您遇到的是正常现象,这就是 NTLM 身份验证方案的工作原理。
1: C --> S GET ...
2: C <-- S 401 Unauthorized
WWW-Authenticate: NTLM
3: C --> S GET ...
Authorization: NTLM <base64-encoded type-1-message>
4: C <-- S 401 Unauthorized
WWW-Authenticate: NTLM <base64-encoded type-2-message>
5: C --> S GET ...
Authorization: NTLM <base64-encoded type-3-message>
6: C <-- S 200 Ok
- 客户端向服务器发送
GET
请求。 - 由于您需要通过身份验证才能访问请求的资源,因此服务器会发回
401 Unathorized
响应并在WWW-Authenticate
header 中通知客户端它支持NTLM
认证。所以这是您获得第一个401
响应代码的地方。 - 客户端在
Authorization
header中向服务器发送域名和用户名。请注意,仅基于这些信息还不能对客户端进行身份验证。 - 服务器向客户端发送质询。这是一个随机生成的数字,称为 nonce。这是您获得第二个
401
响应代码的地方。 - 客户端发回对服务器质询的响应,使用其密码的散列来加密随机数。
- 服务器将客户端的用户名、发送给客户端的质询以及从客户端收到的响应发送给域控制器。使用用户名,域控制器检索用户密码的哈希值并用它加密质询。如果结果与客户端发送的响应匹配,则客户端通过身份验证,服务器向客户端发回
200
响应代码和请求的资源。
遇到了类似的问题,经过大量回答后,none 的答案有效。以下工作正常,但没有出现两个 401:
var credential = new NetworkCredential("username", "password", "domainname");
var myCache = new CredentialCache();
// Add the target Uri to the CredentialCache with credential object
myCache.Add(new Uri("http://targeturi/"), "NTLM", credential);
// Create an HttpClientHandler to add some settings
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = true;
handler.Credentials = myCache;
// Create an HttpClient with the handler object
httpClient = new HttpClient(handler);
// Wait to get the reponse, and you can use the reponse in your code
HttpResponseMessage response = await httpClient.GetAsync(resourceUri);