使用基本身份验证的HttpWebRequest

176

我正在尝试通过一个模拟“基本身份验证请求”的认证请求,这与我们在设置IIS时看到的行为相似。

URL是:https://telematicoprova.agenziadogane.it/TelematicoServiziDiUtilitaWeb/ServiziDiUtilitaAutServlet?UC=22&SC=1&ST=2
(警告:https!)

该服务器在UNIX和Java应用程序服务器下运行。

这是我用来连接到此服务器的代码:

CookieContainer myContainer = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://telematicoprova.agenziadogane.it/TelematicoServiziDiUtilitaWeb/ServiziDiUtilitaAutServlet?UC=22&SC=1&ST=2");
request.Credentials = new NetworkCredential(xxx,xxx);
request.CookieContainer = myContainer;
request.PreAuthenticate = true;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

(我从这个网站上的另一篇帖子中复制了这个问题)。但是服务器返回了如下答案:

底层连接已关闭: 发生了意外错误。

我认为我尝试了我所掌握的 C# 知识可以提供的所有可能的解决方案,但是没有任何作用……


如果你加上了以下代码,我想这个程序就能够工作:request.UseDefaultCredentials = false; - bpeikes
11个回答

362

你也可以自己添加授权头信息。

只需将名称设置为“Authorization”,值设置为“Basic BASE64({USERNAME:PASSWORD})”即可。

var username   = "abc";
var password   = "123";
string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1")
                               .GetBytes(username + ":" + password));
httpWebRequest.Headers.Add("Authorization", "Basic " + encoded);

编辑

根据What encoding should I use for HTTP Basic Authentication?和Jeroen的评论,将编码从UTF-8转换为ISO 8859-1。


4
你如何确定使用UTF8是正确的编码方式? - Jeroen Wiert Pluimers
2
不错的发现。看起来请求认证头应该使用ISO-8859-1进行编码。参考https://dev59.com/0Ww05IYBdhLWcg3wcRUj。 - Zambonilli
1
啊啊啊!1:谢谢,伙计。2. 我真的很想知道为什么其他方法,在CredentialCache中设置身份验证方法根本不起作用。它们应该可以,不是吗? - mshthn
1
所有的 MSDN 文档都指出是的,其他方法应该可以工作。然而,我从未能够让它们工作。 - Zambonilli
对我不起作用(无论是utf-8还是ISO-8859-1)。有什么建议要检查吗?当我执行“webRequest.Credentials = new NetworkCredential(UserID, Password);”时它可以工作。 - RollerCosta
适用于我。我使用与问题中相似的代码时遇到了401(未经授权)的错误。 - aampere

69

我终于明白了!

string url = @"https://telematicoprova.agenziadogane.it/TelematicoServiziDiUtilitaWeb/ServiziDiUtilitaAutServlet?UC=22&SC=1&ST=2";
WebRequest request = WebRequest.Create(url);
request.Credentials = GetCredential();
request.PreAuthenticate = true;

这是GetCredential()函数

private CredentialCache GetCredential()
{
    string url = @"https://telematicoprova.agenziadogane.it/TelematicoServiziDiUtilitaWeb/ServiziDiUtilitaAutServlet?UC=22&SC=1&ST=2";
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
    CredentialCache credentialCache = new CredentialCache();
    credentialCache.Add(new System.Uri(url), "Basic", new NetworkCredential(ConfigurationManager.AppSettings["ead_username"], ConfigurationManager.AppSettings["ead_password"]));
    return credentialCache;
}

太棒了!


35
如果你能使用 WebClient 类,那么基本身份验证就变得简单了:
var client = new WebClient {Credentials = new NetworkCredential("user_name", "password")};
var response = client.DownloadString("https://telematicoprova.agenziadogane.it/TelematicoServiziDiUtilitaWeb/ServiziDiUtilitaAutServlet?UC=22&SC=1&ST=2");

12

试一下这个:

System.Net.CredentialCache credentialCache = new System.Net.CredentialCache(); 
credentialCache.Add(
    new System.Uri("http://www.yoururl.com/"),
    "Basic", 
    new System.Net.NetworkCredential("username", "password")
);

...
...

httpWebRequest.Credentials = credentialCache; 

这绝对是基本授权吗?此外,您是否可以通过浏览器使用用户名/密码访问资源? - MrEyes
它似乎是在HTTPS上进行基本身份验证。如果您单击我提供的链接,浏览器会像在IIS上执行“基本身份验证”或通过Apache在文件夹上使用.htaccss文件时一样弹出“用户名/密码”请求。我尝试使用Fiddler,但我没有头绪。 - Kenny Rullo
我刚刚得知该网站正在使用IBM http服务器运行。这可能是一个有用的消息吗? - Kenny Rullo

8

对于使用RestSharp的人来说,当使用SimpleAuthenticator时可能会失败(可能是由于幕后没有使用ISO-8859-1)。我通过明确发送基本身份验证标头来完成它:

string username = "...";
string password = "...";

public IRestResponse GetResponse(string url, Method method = Method.GET)
{
    string encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes($"{username}:{password}"));
    var client = new RestClient(url);
    var request = new RestRequest(method );
    request.AddHeader("Authorization", $"Basic {encoded}");
    IRestResponse response = client.Execute(request);
    return response;
}

var response = GetResponse(url);
txtResult.Text = response.Content;

6

首先,对于我来说,ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 起作用了,而不是 Ssl3。

其次,我必须发送带有一些数据(表单url编码)的基本身份验证请求。以下是完整的示例,在尝试了许多解决方案后,它对我完美地起作用了。

免责声明:下面的代码是在此链接和其他一些stackoverflow链接上找到的解决方案的混合体,感谢提供有用信息的人。

        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
        String username = "user_name";
        String password = "password";
        String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));

        //Form Data
        var formData = "var1=val1&var2=val2";
        var encodedFormData = Encoding.ASCII.GetBytes(formData);

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("THE_URL");
        request.ContentType = "application/x-www-form-urlencoded";
        request.Method = "POST";
        request.ContentLength = encodedFormData.Length;
        request.Headers.Add("Authorization", "Basic " + encoded);
        request.PreAuthenticate = true;

        using (var stream = request.GetRequestStream())
        {
            stream.Write(encodedFormData, 0, encodedFormData.Length);
        }

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

非常感谢这个答案。对我来说完美地解决了问题!非常感谢!!! - crazynx

4
以下代码将解决具有基本身份验证和代理实现的JSON响应。同时,它还将解决IIS 7.5托管问题。
public string HttpGetByWebRequ(string uri, string username, string password)
{
//For Basic Authentication
    string authInfo = username + ":" + password;
    authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));

//For Proxy
    WebProxy proxy = new WebProxy("http://10.127.0.1:8080", true);

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "GET";
    request.Accept = "application/json; charset=utf-8";
    request.Proxy = proxy;

    request.Headers["Authorization"] = "Basic " + authInfo;

    var response = (HttpWebResponse)request.GetResponse();

    string strResponse = "";
    using (var sr = new StreamReader(response.GetResponseStream()))
    {
        strResponse= sr.ReadToEnd();

    }

    return strResponse;
}

对我不起作用(无论是utf-8还是ISO-8859-1还是默认值)。有什么建议要检查吗?请注意 - 当我执行“webRequest.Credentials = new NetworkCredential(UserID, Password);”时它可以工作。 - RollerCosta

2

1
以下构造在我的情况下不能正常工作:
request.Credentials = new NetworkCredential("user", "pass");

我使用了 CredentialCache
CredentialCache credentialCache = new CredentialCache
{
    {
        new Uri($"http://{request.Host}/"), "Basic",
        new NetworkCredential("user", "pass")
    }
};
request.Credentials = credentialCache;

然而,如果您想添加多个基本认证凭据(例如,如果您知道重定向),您可以使用我制作的以下函数:

private void SetNetworkCredential(Uri uriPrefix, string authType, NetworkCredential credential)
{
    if (request.Credentials == null)
    {
        request.Credentials = new CredentialCache();
    }

    if (request.Credentials.GetCredential(uriPrefix, authType) == null)
    {
        (request.Credentials as CredentialCache).Add(uriPrefix, authType, credential);
    }
}

我希望它能在未来帮助某些人。

0

以下是如何在C#中进行Http Basic Auth字符串的方法

string username = "user";
string password = "pass";            
var basicAuthBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes($"{username}:{password}");
var authHeaderValue = $"Basic {System.Convert.ToBase64String(basicAuthBytes)}";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接