WebClient.DownloadData(uri)HTTP NTLM身份验证失败,401使用正确的凭据

时间:2016-03-25 17:56:57

标签: c# asp.net authentication

我有以下代码:

using (WebClient wcli = new WebClient())
{
    wcli.UseDefaultCredentials = true;
    wcli.Credentials = new NetworkCredential("RS_Username", "RS_Password", "RS_Domain");

    byte[] buff = wcli.DownloadData(www);

    HttpContext.Current.Response.ClearContent();
    HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + reportName + ".pdf\"");
    HttpContext.Current.Response.ContentType = "application/pdf";
    HttpContext.Current.Response.BinaryWrite(buff);
    HttpContext.Current.Response.Flush();
    HttpContext.Current.Response.End();
}

我使用它获取SSRS 2014中的报告结果,并将其作为文档从我的Web应用程序下载(在.Net 3.5中,托管在Window 8.1,IIS 8.5上)。

我遇到的问题是,在调用wcli.DownloadData(www)时,我一直收到 401 Unauthorized (注意使用任何浏览器,报告在使用的凭据下工作正常) 我已经完成了TCP转储,我发现NTLM握手没有发生:

  1. C - > S:GET请求
  2. C< - S:'401 Unauthorized'回复标题 'WWW-Authenticate:NTLM'
  3. 没有别的
  4. 托管在同一台机器上但使用.Net 4.5的另一个应用程序使用相同的代码而没有任何问题。

    我认为它必须是由于缺少/错误的配置,但我没有成功找出哪一个。 有什么想法吗?

    更新

    我忘记提到的是,所提到的两个Web应用程序(都在同一服务器和IIS上托管)都连接到同一个Reporting Services服务器(但是不同的文件夹)。

2 个答案:

答案 0 :(得分:0)

您告诉WebClient使用DefaultCredentials。 wcli.UseDefaultCredentials = true;但您也传递了NetworkCredential。也许其他可用的代码,如果它们都使用相同的代码,则可以正常工作,因为它的用户可以访问。

using (WebClient wcli = new WebClient())
{
    wcli.UseDefaultCredentials = true;
    wcli.Credentials = new NetworkCredential("RS_Username", "RS_Password", "RS_Domain");
}

然而,这可能不是你的错误。发现这篇文章:http://www.benjaminathawes.com/2010/10/14/ntlms-dependency-on-http-keep-alives-another-cause-of-the-dreaded-401-1-error/

它提到需要使用HTTP keep-alive来保持TCP连接为NTLM握手打开。握手刚刚死亡这一事实让我觉得这可能也是问题所在。我会检查以确认保持活着的确存在。

答案 1 :(得分:0)

我遇到了同样的问题,在我的案例中(Still .Net4.5)有什么用处:

WebClient wc = new WebClient();  
wc.UseDefaultCredentials = false;
string host = "http://localhost"; //this comes from a function in my code
var myCredentialCache = new System.Net.CredentialCache();
myCredentialCache.Add(new Uri(host + "/"), "NTLM", new System.Net.NetworkCredential(accessUser, accessPassword, domain));

wc.Credentials = myCredentialCache;

var result = wc.DownloadFile(www);

我的主要区别是使用CredentialCache并设置主机uri,也是网络凭证中的域