根据MSDN,当HttpWebRequest.AllowAutoRedirect
属性为true时,重定向将清除身份验证标头。给出的解决方法是实现IAuthenticationModule来处理身份验证:
在自动重定向时清除Authorization标头,HttpWebRequest会自动尝试重新向重定向位置进行身份验证。实际上,这意味着如果可能遇到重定向,则应用程序无法将自定义身份验证信息放入Authorization标头中。相反,应用程序必须实现并注册自定义身份验证模块。 System.Net.AuthenticationManager和相关类用于实现自定义身份验证模块。 AuthenticationManager.Register方法注册自定义身份验证模块。
我创建了这个界面的基本实现:
public class CustomBasic : IAuthenticationModule
{
public CustomBasic() { }
public string AuthenticationType { get { return "Basic"; } }
public bool CanPreAuthenticate { get { return true; } }
private bool checkChallenge(string challenge, string domain)
{
if (challenge.IndexOf("Basic", StringComparison.InvariantCultureIgnoreCase) == -1) { return false; }
if (!string.IsNullOrEmpty(domain) && challenge.IndexOf(domain, StringComparison.InvariantCultureIgnoreCase) == -1) { return false; }
return true;
}
public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
{
return authenticate(request, credentials);
}
public Authorization Authenticate(String challenge, WebRequest request, ICredentials credentials)
{
if (!checkChallenge(challenge, string.Empty)) { return null; }
return this.authenticate(request, credentials);
}
private Authorization authenticate(WebRequest webRequest, ICredentials credentials)
{
NetworkCredential requestCredentials = credentials.GetCredential(webRequest.RequestUri, this.AuthenticationType);
return (new Authorization(string.Format("{0} {1}", this.AuthenticationType, Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", requestCredentials.UserName, requestCredentials.Password))))));
}
}
和一个简单的驱动程序来运用该功能:
public class Program
{
static void Main(string[] args)
{
// replaces the existing handler for Basic authentication
AuthenticationManager.Register(new CustomBasic());
// make a request that requires authentication
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"https://www.SomeUrlThatRequiresAuthentication.com");
request.Method = "GET";
request.KeepAlive = false;
request.ContentType = "text/plain";
request.AllowAutoRedirect = true;
request.Credentials = new NetworkCredential("userName", "password");
HttpWebResponse result = (HttpWebResponse)request.GetResponse();
}
}
当我发出不重定向的请求时,我的类上的Authenticate
方法被调用,并且身份验证成功。当我提出重新启动307(临时重定向)响应的请求时,不会调用我的类的方法,并且身份验证失败。这是怎么回事?
我宁愿不禁用自动重定向并编写自定义逻辑来自行处理3xx响应。如何让我的身份验证逻辑与自动重定向一起使用?
答案 0 :(得分:6)
代替NetworkCredential,您应该为request.Credentials传递CredentialCache。
CredentialCache cache = new CredentialCache();
cache.Add(new Uri(@"https://www.SomeUrlThatRequiresAuthentication.com", "Basic", new NetworkCredential("username", "password"));
request.Credentials = cache;
根据MSDN文档:
CredentialCache类存储多个Internet的凭据 资源。需要访问多个资源的应用程序可以 将这些资源的凭据存储在CredentialCache中 然后,实例提供适当的凭据集 需要时的Internet资源。当GetCredential方法是 在调用时,它比较统一资源标识符(URI)和 身份验证类型提供存储在缓存中的那些 返回匹配的第一组凭据。
答案 1 :(得分:0)
我希望以下是我从代码项目网址http://www.codeproject.com/Articles/49243/Handling-Cookies-with-Redirects-and-HttpWebRequest
中获取的另一个选项 String targetUrl = "https://www.SomeUrlThatRequiresAuthentication.com";
HttpWebRequest request = GetNewRequest(targetUrl);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
while (response.StatusCode == HttpStatusCode.MovedPermanently)
{
response.Close();
request = GetNewRequest(response.Headers["Location"]);
response = (HttpWebResponse)request.GetResponse();
}
private static HttpWebRequest GetNewRequest(string targetUrl)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(targetUrl);
request.AllowAutoRedirect = false;
request.Headers.Add("Authorization", "Basic xxxxxxxx");
return request;
}
答案 2 :(得分:0)
即使OP很老,我也会提名Crater的答案作为答案。我经历了类似的旋转,包括创建自定义身份验证模块,即使我访问的Web资源只使用了基本身份验证。我发现只有在我使用CredentialCache而不是简单的NetworkCredential后,才会在重定向后调用我的身份验证模块。
此外,我发现由于我需要的身份验证是Basic,只需提供CredentialCache,我根本不需要自定义身份验证模块 - 标准的Basic模块工作正常。
以下资源似乎证实了这一点(与OP中提到的.NET文档参考相反):
https://blogs.msdn.microsoft.com/ncl/2009/05/05/custom-http-authentication-schemes/
答案 3 :(得分:-2)
您需要做的是POST
次请求。您要发布要进行身份验证的变量,因此您需要使用POST
操作。
有关详情,请参阅此帖子:Login to website, via C#
自动重定向不应妨碍此帖子请求。我建议安装Fiddler并手动登录,然后观察会发生什么。
*请注意,在发送POST
请求时,如果有登录表单,您就会将POST
请求发送到表单中的action='/some-url-or-whatever.php'
标记。 POST
数据,你应该可以正常登录。
如果有帮助,请告诉我。