繁体   English   中英

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

[英]C# WebClient NTLM authentication starting for each request

考虑一个简单的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重用现有连接以避免重新验证每个请求?

经过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

您是否检查了localhost 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;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM