【问题标题】:How to 'share' NTLM authentication across multiple HttpWebRequests?如何在多个 HttpWebRequest 之间“共享”NTLM 身份验证?
【发布时间】:2011-08-31 11:17:45
【问题描述】:

我的 C# 应用访问了使用 NTLM 身份验证的 Web 服务器。

我发现向服务器发出的每个请求(使用新的 HttpWebRequest)都经过单独身份验证。换句话说,每个请求都会导致 401 响应,然后在我得到实际响应之前发生 NTLM 握手对话。

例如:

第一个 GET 请求:

-> GET xyz 
<- 401 error (WWW-Authenticate:NTLM)

-> GET xyz (Authorization:NTLM base64stuff)
<- 401 error (WWW-Authenticate:NTLM base64stuff)

-> GET xyz (Authorization: base64stuff)
<- 200

后续请求:

-> GET xyz (Authorization:NTLM base64stuff)
<- 401 error (WWW-Authenticate:NTLM) //can this request be avoided?

-> GET xyz (Authorization: base64stuff)
<- 200

(最初,PreAuthenticate 设置为 false,后续请求看起来像第一个请求 - 即每个“请求”三个底层请求)

有没有办法与后续的 HttpWebRequests“共享”对服务器的第一个请求执行的身份验证?

我认为UnsafeAuthenticatedConnectionSharing 属性可能允许我这样做,但是对于应用程序中使用的所有 HttpWebRequest 对象将其设置为 true 无效。

但是,如果我将 PreAuthenticate 设置为 true,则在第一个请求之后的每个请求都会少一个 401 响应。

【问题讨论】:

  • 我想有效地“进行身份验证”一次,并在 HttpWebRequests 中重用它。而不是每次我访问服务器时都进行身份验证。不过,我可能误解了 NTLM,实际上 NTLM 对每个请求都施加了额外请求的开销。
  • 它最初工作方式的问题是对服务器的每个请求都会导致 3 个底层 HTTP 请求/响应。将 PreAuthenticate 设置为 True,它会下降到 2。但是应用程序是否可以“修复”以便每个 HTTP 请求只发出一个请求/响应(当然,除了初始请求)?如果可能,我想避免每个 HTTP 请求两个请求所涉及的网络流量开销。
  • @Ben:每个额外的请求都意味着到服务器的一次往返。虽然这并不意味着太多的流量,但它会降低每个请求的速度 - 从发送请求到准备好响应之间的持续时间几乎翻了一番,即使在快速连接中也是如此。
  • @Ben 在我看来,几十毫秒是一个非常非常长的时间!是的,程序员倾向于在他们的代码中进行许多不需要的优化,这可能会节省一些时钟周期。但是考虑一下今天的 CPU 每毫秒可以进行多少计算。 50ms 的时间对用户来说是相当明显的,优化它们是让软件变得活泼的原因。另外,如果吞吐量很重要(您按顺序发出许多请求),这将使请求/秒加倍。所以,基本上我同意你的观点,但它取决于用例的要求。
  • @Ben IMO 如果可能的话,服务器往返值得优化。我不会称其为微优化。但是,如果我找不到解决方案 - 这不是世界末日!

标签: c# httpwebrequest ntlm networkcredentials


【解决方案1】:

执行 NTLM 后发送的最后一个请求(导致 200 响应的请求)包含一个 auth 标头,告诉服务器您拥有正确的凭据。

我不确定客户端类是否具有自行保留此标头的功能,但如果您找到某种方法来保留此标头并将其添加到您的后续请求中,它应该可以正常工作。


更新:NTLM 对连接进行身份验证,因此您需要使用 Keep-Alive 标头保持连接打开。客户端类应该为此提供一些设置。有关更多信息,请参阅此页面,我发现该页面对 NTLM 方案非常有用且清晰:

http://www.innovation.ch/personal/ronald/ntlm.html

【讨论】:

  • 嗯。可以在 HttpWebRequest 上设置 Authorization 标头,我尝试过。但是它不起作用 - 服务器返回 400 Bad Request,表示无法以这种方式“重放”授权标头。出于安全原因,我认为这是有道理的。
  • 在做了一些测试之后,看起来,虽然 HttpWebRequest 有一个 KeepAlive 属性,但它并没有比设置 PreAuthenticate=true 更好。有点烦人。
  • @mackenir:你解决了这个问题吗?我也看到了与您上面描述的完全相同的问题。将 PreAuthenticate 和 KeepAlive 设置为 true 似乎没有帮助。
【解决方案2】:

也许有点晚了,但你必须在 WebRequestHandler 中将UnsafeAuthenticatedConnectionSharing 属性设置为 true(它扩展了 HttpClientHandler)。

这种方式通过允许 HttpClient 在其他请求之间“共享”身份验证来保持连接,同时允许连接保持活动状态(即使您自己设置标头也不能手动执行此操作)。请记住,您还应该在服务器中拥有适当的持久授权,对于 Kerberos 使用 authPersistNonNTLM 或对于 NTLM 使用 authPersistSingleRequest

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 2011-10-10
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    相关资源
    最近更新 更多