如何使用HttpWebRequest.AllowAutoRedirect处理身份验证?

时间:2012-10-31 13:53:28

标签: c# http authentication redirect

根据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响应。如何让我的身份验证逻辑与自动重定向一起使用?

4 个答案:

答案 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数据,你应该可以正常登录。

如果有帮助,请告诉我。