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

标签 c# .net authentication webclient ntlm

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

  • 使用网络客户端
  • 使用 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” header ,整个身份验证/授权过程重复;没有“Connection: close” header )。

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

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

最佳答案

在尝试了 10 天我能想到的所有方法并在此过程中学到了很多东西之后,我终于找到了解决此问题的方法。

诀窍是启用UnsafeAuthenticatedConnectionSharing通过重写 GetWebRequest 并将 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 {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所有的帮助;虽然他的建议对我来说不太奏效,但他确实为我指明了寻找并最终找到答案的正确方向。

关于为每个请求启动 C# WebClient NTLM 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39787404/

相关文章:

c# - 如何以编程方式执行 Word Automation Services?

c# - 在哪里可以了解有关 P/Invoke 的更多信息?

c# - 中继 JSON 已转义双引号

c# - ASP.Net MVC : Submit array/collection in a single parameter

node.js - 使用 Passport 进行身份验证后创建新 session

c# - 在 Windows 应用程序中使用 C# 绘制条形图

java - .Net 客户端与使用原始数据的 Java 服务器

c# - 使用 out 的通用类型参数

python - 登录后重定向只需附加 LOGIN_REDIRECT_URL

javascript - 无法从 ApolloClient 中的 localStorage 检索更新的 token