【问题标题】:C# WebClient NTLM authentication starting for each requestC# WebClient NTLM 身份验证从每个请求开始
【发布时间】:2016-09-30 08:51:14
【问题描述】:

考虑一个简单的 C# NET Framework 4.0 应用程序:

  • 使用 WebClient
  • 使用 NTLM 进行身份验证(在 IIS 6.0 和 IIS 7.5 服务器上测试)
  • 使用 DownloadString() 多次从 URL 中检索字符串

这是一个运行良好的示例:

using System;
using System.Net;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string URL_status = "http://localhost/status";

            CredentialCache myCache = new CredentialCache();
            myCache.Add(new Uri(URL_status), "NTLM", new NetworkCredential("username", "password", "domain"));

            WebClient WebClient = new WebClient();
            WebClient.Credentials = myCache;

            for (int i = 1; i <= 5; i++)
            {
                string Result = WebClient.DownloadString(new Uri(URL_status));
                Console.WriteLine("Try " + i.ToString() + ": " + Result);
            }

            Console.Write("Done");
            Console.ReadKey();
        }
    }
}

问题:

启用跟踪时,我发现 NTLM 身份验证没有持续。

每次调用 Webclient.DownloadString 时,NTLM 身份验证开始(服务器返回“WWW-Authenticate: NTLM”标头,整个身份验证/授权过程重复;没有“Connection: close”标头)。

NTLM 不应该对连接而不是请求进行身份验证吗?

有没有办法让 WebClient 重用现有的连接以避免重新验证每个请求?

【问题讨论】:

    标签: c# .net authentication webclient ntlm


    【解决方案1】:

    在尝试了我能想到的一切并在此过程中学到了很多东西 10 天之后,我终于想出了解决这个问题的办法。

    诀窍是通过覆盖GetWebRequest 并将true 中的属性设置为true 来启用UnsafeAuthenticatedConnectionSharing,然后返回。

    您可能希望将其与 ConnectionGroupName 属性结合使用,以避免未经身份验证的应用程序可能使用连接。

    这是修改后可以按预期工作的问题示例。它会打开一个经过 NTLM 身份验证的连接并重用它:

    using System;
    using System.Net;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string URL_status = "http://localhost/status";
    
                CredentialCache myCache = new CredentialCache();
                myCache.Add(new Uri(URL_status), "NTLM", new NetworkCredential("username", "password", "domain"));
    
                MyWebClient webClient = new MyWebClient();
                webClient.Credentials = myCache;
    
                for (int i = 1; i <= 5; i++)
                {
                    string result = webClient.DownloadString(new Uri(URL_status));
                    Console.WriteLine("Try {0}: {1}", i, result);
                }
    
                Console.Write("Done");
                Console.ReadKey();
            }
        }
    
        public class MyWebClient : WebClient
        {
            protected override WebRequest GetWebRequest(Uri address)
            {
                WebRequest request = base.GetWebRequest(address);
    
                if (request is HttpWebRequest) 
                {
                    var myWebRequest = request as HttpWebRequest;
                    myWebRequest.UnsafeAuthenticatedConnectionSharing = true;
                    myWebRequest.KeepAlive = true;
                }
    
                return request;
            }
        }   
    }
    

    在此我还要感谢@Falco Alexander的所有帮助;虽然他的建议对我不太奏效,但他确实为我指明了寻找并最终找到答案的正确方向。

    【讨论】:

      【解决方案2】:

      检查您的 IIS 设置,虽然这应该是默认设置。

      <windowsAuthentication
         enabled="True"
         authPersistSingleRequest="False"
         UseKernelMode>
      
      </windowsAuthentication>  
      

      参考:https://msdn.microsoft.com/en-us/library/aa347472.aspx

      您是否检查了 localhost IIS 所在的区域?这也是过去使用 WinInet 时客户端的一个陷阱。检查WebClient 的默认行为。


      编辑:

      在重现错误后,我可以确定是 WebClient 的缺失 NTLM preauthentication 实现使您无法收到单个 401 请求:

      var WebClient = new PreAuthWebClient();
      WebClient.Credentials = new NetworkCredential("user", "pass","domain");
      
      //Do your GETs 
      
      Public class PreAuthWebClient: WebClient
      {
          protected override WebRequest GetWebRequest (Uri address)
          {
              WebRequest request = (WebRequest) base.GetWebRequest (address);
              request.PreAuthenticate = true;
              return request;
        }
      }
      

      【讨论】:

      • IIS 设置为默认值;我只是尝试手动禁用 authPersistSingleRequest 并且没有任何更改 - 我使用 WebClient 发出的每个请求仍然单独进行身份验证。如果它连接到同一台机器或不同机器上的 IIS,也会发生同样的事情。身份验证成功并且有效,但每个请求都经过身份验证,而不仅仅是第一个。
      • P.s.:如果我尝试使用 Firefox 访问相同的 URL,它会按预期工作:第一个请求得到 401,然后在身份验证/授权交换之后,所有后续请求都是 200/304 响应,所以它不应该是服务器配置问题。
      • 如果您检查您的 fireFox 会话,在第一次请求后是否存在持续存在的身份验证 cookie?这将导致默认 WebClient 无法识别 cookie。检查 WebRequest 或谷歌的“Cookie 感知 WebClient”
      • 服务器未设置任何 cookie(无论是在 Firefox 中,还是在检查应用程序跟踪中的标头时)。
      • 认证成功后服务器发送的Headers(连同200响应码):Accept-Ranges: bytes Date: Fri, 30 Sep 2016 11:04:00 GMT Etag: "126c7343821ad21:0" Last-Modified: Thu, 29 Sep 2016 18:49:52 GMT Persistent-Auth: true Server: Microsoft-IIS/7.5 X-Powered-By: ASP.NET
      猜你喜欢
      • 1970-01-01
      • 2022-11-04
      • 1970-01-01
      • 1970-01-01
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多