[英]Why would my REST service .NET clients send every request without authentication headers and then retry it with authentication header?
We happen to run a REST web service with API requiring that clients use Basic authentication. 我们碰巧运行带有API的REST Web服务,要求客户端使用基本身份验证。 We crafted a set of neat samples in various languages showing how to interface with our service.
我们用各种语言制作了一套简洁的样本,展示了如何与我们的服务进行交互。 Now I'm reviewing IIS logs of the service and see that the following pattern happens quite often:
现在我正在检查服务的IIS日志,并发现以下模式经常发生:
which looks like the first request is sent without Authorization headers and then the second one is sent with the right headers and succeeds. 看起来像第一个请求没有授权标头发送,然后第二个请求与正确的标头一起发送并成功。 Most of the time the log record contains "user-agent" which is the same string we planted into our .NET sample.
大多数情况下,日志记录包含“user-agent”,这与我们在.NET示例中植入的字符串相同。
So I assume the problem is with .NET programs only. 所以我认为问题仅在于.NET程序。 The problem is not reproduced with our sample code so I assume the users somehow modified the code or wrote their own from scratch.
我们的示例代码没有重现该问题,因此我假设用户以某种方式修改了代码或从头开始编写自己的代码。
We tried contacting the users but apparently they don't want to invest time into research. 我们尝试联系用户,但显然他们不想花时间研究。 So it'd be nice to find what the most likely scenario is which leads to this behavior of .NET programs.
所以很高兴找到导致.NET程序这种行为的最可能的情况。
Why would they do this? 他们为什么要这样做? Why would they not attach the headers on the first attempt?
他们为什么不在第一次尝试时附上标题?
This is the default behavior of HttpClient
and HttpWebRequest
classes which is exposed the following way. 这是
HttpClient
和HttpWebRequest
类的默认行为,它们以下列方式公开。
Note: Below text explains suboptimal behavior causing the problem described in the question. 注意:下面的文字解释了导致问题中描述的问题的次优行为。 Most likely you should not write your code like this.
很可能你不应该像这样写你的代码。 Instead scroll below to the corrected code
而是向下滚动到更正的代码
In both cases, instantiate a NetworkCredenatial
object and set the username and password in there 在这两种情况下,都要实例化
NetworkCredenatial
对象并在其中设置用户名和密码
var credentials = new NetworkCredential( username, password );
If you use HttpWebRequest
- set .Credentials
property: 如果您使用
HttpWebRequest
- 设置.Credentials
属性:
webRequest.Credentials = credentials;
If you use HttpClient
- pass the credentials object into HttpClientHandler
(altered code from here ): 如果您使用
HttpClient
- 将凭证对象传递给HttpClientHandler
( 此处更改的代码):
var client = new HttpClient(new HttpClientHandler() { Credentials = credentials })
Then run Fiddler and start the request. 然后运行Fiddler并启动请求。 You will see the following:
您将看到以下内容:
This behavior is explained here - the client doesn't know in advance that the service requires Basic and tries to negotiate the authentication protocol (and if the service requires Digest sending Basic headers in open is useless and can compromise the client). 此处解释了此行为 - 客户端事先并不知道该服务需要Basic并尝试协商身份验证协议(如果服务需要Digest在open中发送Basic头,则无用且可能危及客户端)。
Note: Here suboptimal behavior explanation ends and better approach is explained. 注意:这里次优的行为解释结束,并解释了更好的方法。 Most likely you should use code from below instead of code from above.
您最有可能使用下面的代码而不是上面的代码。
For cases when it's known that the service requires Basic that extra request can be eliminated the following way: 对于已知服务需要Basic的情况 ,可以通过以下方式消除额外请求:
Don't set .Credentials
, instead add the headers manually using code from here . 不要设置
.Credentials
,而是使用此处的代码手动添加标题。 Encode the username and password: 编码用户名和密码:
var encoded = Convert.ToBase64String( Encoding.ASCII.GetBytes(
String.Format( "{0}:{1}", username, password ) ) );
When using HttpWebRequest
add it to the headers: 使用
HttpWebRequest
将其添加到标题中:
request.Headers.Add( "Authorization", "Basic " + encoded );
and when using HttpClient
add it to default headers: 并在使用
HttpClient
将其添加到默认标头:
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue( "Basic", encoded );
When you do that the request is sent with the right authorization headers every time. 执行此操作时,每次都会使用正确的授权标头发送请求。 Note that you should not set
.Credentials
, otherwise if the username or password is wrong the same request will be sent twice both time with the wrong credentials and both times of course yielding HTTP 401. 请注意,您不应设置
.Credentials
,否则如果用户名或密码错误,则同一请求将在错误凭据的两次发送两次,当然两次都会产生HTTP 401。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.