首页 文章

每个请求的C#WebClient NTLM身份验证启动

提问于
浏览
9

考虑一个简单的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();
        }
    }
}

The problem:

启用跟踪时,我发现NTLM身份验证不会持久存在 .

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

是不是NTLM应该验证连接,而不是请求?

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

2 回答

  • 1

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

    诀窍是通过重写 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 " + i.ToString() + ": " + Result);
                }
    
                Console.Write("Done");
                Console.ReadKey();
            }
        }
    
        public class MyWebClient : WebClient
        {
            protected override WebRequest GetWebRequest(Uri address)
            {
                WebRequest request = (WebRequest)base.GetWebRequest(address);
    
                if (request is HttpWebRequest) 
                {
                    var myWebRequest = request as HttpWebRequest;
                    myWebRequest.UnsafeAuthenticatedConnectionSharing = true;
                    myWebRequest.KeepAlive = true;
                }
    
                return request;
            }
        }   
    }
    

    在这一点上,我还要感谢@Falco Alexander的所有帮助;虽然他的建议对我不起作用,但他确实指出了我正确的方向寻找并最终找到答案 .

  • 11

    检查你的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;
      }
    }
    

相关问题