c# WebClient NTLM身份验证为每个请求启动

本文关键字:请求 启动 WebClient NTLM 身份验证 | 更新日期: 2023-09-27 18:09:33

考虑一个简单的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# WebClient NTLM身份验证为每个请求启动

经过10天的尝试,我能想到的一切,并在此过程中学到了很多,我终于找到了解决这个问题的方法。

技巧是通过覆盖GetWebRequest并将您返回的HttpWebRequest中的属性设置为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的所有帮助;虽然他的建议对我来说不太奏效,但他确实为我指明了寻找并最终找到答案的正确方向。

检查您的IIS设置,尽管这应该是默认设置。

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

裁判:https://msdn.microsoft.com/en-us/library/aa347472.aspx

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


编辑:

再现错误后,我可以弄清楚这是WebClient的缺失的NTLM 预认证实现,使您无法进行单个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;
  }
}