2014-09-10 26 views
14

我们碰巧使用API​​来运行REST Web服务,要求客户端使用基本身份验证。我们制作了一系列各种语言的精美样本,展示了如何与我们的服务进行交互。现在我回顾了服务的IIS日志,看到下面的模式常有发生:为什么我的REST服务.NET客户端发送没有验证头的每个请求,然后用身份验证头重试它?

  • 收到请求时,获取与HTTP代码拒绝401
  • 相同的请求重新发送并成功

看起来像第一个请求发送没有授权标题,然后第二个与正确的标题发送并成功。大多数情况下,日志记录包含“user-agent”,这是我们种植到.NET示例中的相同字符串。

所以我假设问题只与.NET程序有关。我们的示例代码没有重现问题,因此我假设用户以某种方式修改了代码或从头编写了自己的代码。

我们尝试联系用户,但显然他们不想投入时间研究。所以很高兴找到导致.NET程序行为的最可能的场景。

他们为什么要这样做?他们为什么不在第一次尝试时附上标题?

回答

31

这是HttpClientHttpWebRequest类的默认行为,其暴露方式如下。

注意:下面的文字说明导致问题中描述的问题的次优行为。很可能你不应该这样写你的代码。相反,下面滚动到更正后的代码

在这两种情况下,实例化一个NetworkCredenatial对象,并设置有

var credentials = new NetworkCredential(username, password); 

如果使用HttpWebRequest的用户名和密码 - 设置.Credentials属性:

webRequest.Credentials = credentials; 

如果您使用HttpClient - 将凭证对象传递到HttpClientHandler(从here更改的代码):

var client = new HttpClient(new HttpClientHandler() { Credentials = credentials }) 

然后运行Fiddler并开始请求。您将看到以下内容:

  • 请求不授权头发送
  • 服务回复与HTTP 401和WWW身份验证:基本境界=“UrRealmHere”
  • 请求重新发送适当授权标题(和成功)

这种现象是说明here - 的CLIE nt事先并不知道该服务需要基本并试图协商认证协议(如果服务需要摘要发送基本打开头文件是无用的,可以危害客户端)。

注意:这里次优行为解释结束,并解释更好的方法。很可能你应该使用下面的代码而不是上面的代码。

的案件时,它知道该服务需要基本额外的要求可以消除通过以下方式:

不要设置.Credentials,而不是使用代码手动添加here头。编码的用户名和密码:

var encoded = Convert.ToBase64String(Encoding.ASCII.GetBytes(
    String.Format("{0}:{1}", username, password))); 

当使用HttpWebRequest将它添加到标题:

request.Headers.Add("Authorization", "Basic " + encoded); 

,并使用HttpClient时将其添加到默认的标题:

client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", encoded); 

当你这样做该请求每次都发送正确的授权标头。请注意,您不应设置.Credentials,否则如果用户名或密码错误相同的请求将双方的时间与错误的凭据,当然产生HTTP的两次发送两次401

+1

此解决方案以及它允许在第一个请求上设置授权标头,从而绕过401挑战/响应。但是,根据我对HttpClient和HttpClientHandler的经验,设置预认证的工作方式是,401挑战/响应完成后,每个请求都设置Authorize头。这篇文章解释得很好:http://weblog.west-wind.com/posts/2010/Feb/18/NET-WebRequestPreAuthenticate-not-quite-what-it-sounds-like – Philippe 2014-09-24 21:42:57

+0

@Philippe:是的,太。谢谢。 – sharptooth 2014-09-26 12:31:40

+0

提示:对于代理,您应该设置'client.DefaultRequestHeaders.ProxyAuthorization'标头。 – stil 2015-11-13 18:36:01

相关问题