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

C# 如何使用HttpWebRequest.AllowAutoRedirect处理身份验证?,c#,http,authentication,redirect,C#,Http,Authentication,Redirect,根据,当HttpWebRequest.AllowAutoRedirect属性为true时,重定向将清除身份验证头。给出的解决方法是实现IAAuthenticationModule来处理身份验证: 自动重定向时会清除授权标头,HttpWebRequest会自动尝试重新验证重定向位置。实际上,这意味着如果可能遇到重定向,应用程序无法将自定义身份验证信息放入授权头中。相反,应用程序必须实现并注册自定义身份验证模块。System.Net.AuthenticationManager和相关类用于实现自定义身

根据,当HttpWebRequest.AllowAutoRedirect属性为true时,重定向将清除身份验证头。给出的解决方法是实现IAAuthenticationModule来处理身份验证:

自动重定向时会清除授权标头,HttpWebRequest会自动尝试重新验证重定向位置。实际上,这意味着如果可能遇到重定向,应用程序无法将自定义身份验证信息放入授权头中。相反,应用程序必须实现并注册自定义身份验证模块。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响应。如何使身份验证逻辑与自动重定向一起工作?

您需要做的可能是一个
POST
请求。您正在发布变量以进行身份验证,因此需要使用
POST
操作

有关更多信息,请参阅本文:

自动重定向不应妨碍此post请求。我建议安装Fiddler并手动登录,然后观察发生了什么

*请记住,在发送
POST
请求时,如果有登录表单,则将
POST
请求发送到表单中的
action='/some url或任何.php'
标记
POST
将数据发送到该页面,您应该可以很好地登录


如果有帮助,请告诉我。

您应该传递request.Credentials的CredentialCache来代替NetworkCredential

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)和 与存储在缓存中的身份验证一起提供的身份验证类型,以及 返回匹配的第一组凭据


我希望下面是我从代码项目url中选择的另一个选项


尽管OP已经很老了,但我还是会提名陨石坑的反应作为答案。我经历了类似的循环,包括创建自定义身份验证模块,尽管我访问的web资源只使用基本身份验证。我发现,只有在使用CredentialCache而不是简单的NetworkCredential之后,我的身份验证模块才在重定向后被调用

此外,我发现由于我需要的身份验证是基本的,因此仅提供CredentialCache,我根本不需要自定义身份验证模块——标准的基本模块工作得很好

以下资源似乎证实了这一点(与OP中提到的.NET文档参考相比):


当您将keepAlive设置为true而不是false时,是否可以尝试此操作?或者将重定向URL放在请求行中?我对此不太了解,但可能会有所帮助。我也遇到了同样的问题,正在寻找解决方案。这个答案与问题无关。这个问题特别询问在重定向过程中是否清除了身份验证头。在进一步的测试和编码中,似乎对于某些重定向来说,仅仅提供一个CredentialCache是不够的。例如,如果重定向到其他端口,则内置基本身份验证模块似乎无法进行身份验证。如果需要转到另一个端口,则仍然需要自定义模块。和以前一样,您必须提供一个CredentialCache才能调用代码。
    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;
}