Проверка подлинности NTLM WebClient c# начинается для каждого запроса

рассмотрим простое приложение c# NET Framework 4.0, которое:

  • использует WebClient
  • аутентифицируется с помощью NTLM (проверено на IIS 6.0 и IIS 7.5 server)
  • извлекает строку из URL несколько раз с помощью DownloadString ()

вот пример, который прекрасно работает:

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.Вызывается строка загрузки, запускается аутентификация NTLM (сервер возвращает заголовок "WWW-Authenticate: NTLM" и весь процесс аутентификации/авторизации повторяется; нет заголовка "Connection: close").

разве NTLM не должен был аутентифицировать соединение, а не запрос?

есть ли способ сделать WebClient повторно использовать существующее соединение, чтобы избежать повторной аутентификации каждого запроса?

2 ответов


после 10 дней пробовать все, что я мог думать и учиться много в этом процессе, я наконец-то решил исправить эту проблему.

фокус в том, чтобы включить UnsafeAuthenticatedConnectionSharing переопределив HttpWebRequest и установка значения свойства true.

вы можете объединить это с 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 за всю помощь; хотя его предложения не совсем сработали для меня, он указал мне в правильном направлении, чтобы искать и, наконец, найти ответ.


проверьте настройки IIS, например, хотя это должно быть по умолчанию.

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

</windowsAuthentication>  

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

вы проверили зону вашего localhost IIS в? Это была ошибка со стороны клиента в прошлом при работе с wininet. Проверьте поведение WebClient по умолчанию.


Edit:

после воспроизведения ошибки я мог бы выяснить, что это недостающий NTLM предварительная проверка реализация WebClient, который держит вас от одного запроса 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;
  }
}