简体   繁体   English

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

[英]How to handle authenticatication with HttpWebRequest.AllowAutoRedirect?

According to MSDN , when HttpWebRequest.AllowAutoRedirect property is true, redirects will clear authentication headers. 根据MSDN ,当HttpWebRequest.AllowAutoRedirect属性为true时,重定向将清除身份验证标头。 The workaround given is to implement IAuthenticationModule to handle authentication: 给出的解决方法是实现IAuthenticationModule来处理身份验证:

The Authorization header is cleared on auto-redirects and HttpWebRequest automatically tries to re-authenticate to the redirected location. 在自动重定向时清除Authorization标头,HttpWebRequest会自动尝试重新验证重定向的位置。 In practice, this means that an application can't put custom authentication information into the Authorization header if it is possible to encounter redirection. 实际上,这意味着如果可能遇到重定向,则应用程序无法将自定义身份验证信息放入Authorization标头中。 Instead, the application must implement and register a custom authentication module. 相反,应用程序必须实现并注册自定义身份验证模块。 The System.Net.AuthenticationManager and related class are used to implement a custom authentication module. System.Net.AuthenticationManager和相关类用于实现自定义身份验证模块。 The AuthenticationManager.Register method registers a custom authentication module. AuthenticationManager.Register方法注册自定义身份验证模块。

I created a basic implementation of this interface: 我创建了这个接口的基本实现:

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))))));
    }
}

and a simple driver to exercise the functionality: 和一个简单的驱动程序来运用该功能:

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();
    }
}

When I make a request that doesn't redirect, the Authenticate method on my class is called, and authentication succeeds. 当我发出不重定向的请求时,我的类上的Authenticate方法被调用,并且身份验证成功。 When I make a request that reutrns a 307 (temporary redirect) response, no methods of my class are called, and authentication fails. 当我提出重新启动307(临时重定向)响应的请求时,不会调用我的类的方法,并且身份验证失败。 What's going on here? 这里发生了什么?

I'd rather not disable auto redirect and write custom logic to handle 3xx responses myself. 我宁愿不禁用自动重定向和编写自定义逻辑来自己处理3xx响应。 How can I get my authentication logic to work with auto redirect? 如何让我的身份验证逻辑与自动重定向一起使用?

In place of the NetworkCredential, you should pass a CredentialCache for the request.Credentials. 代替NetworkCredential,您应该为request.Credentials传递CredentialCache。

CredentialCache cache = new CredentialCache();
cache.Add(new Uri(@"https://www.SomeUrlThatRequiresAuthentication.com", "Basic", new NetworkCredential("username", "password"));
request.Credentials = cache;

According to the MSDN documentation: 根据MSDN文档:

The CredentialCache class stores credentials for multiple Internet resources. CredentialCache类存储多个Internet资源的凭据。 Applications that need to access multiple resources can store the credentials for those resources in a CredentialCache instance that then provides the proper set of credentials to the Internet resource when required. 需要访问多个资源的应用程序可以将这些资源的凭据存储在CredentialCache实例中,然后在需要时为Internet资源提供适当的凭据集。 When the GetCredential method is called, it compares the Uniform Resource Identifier (URI) and authentication type provided with those stored in the cache and returns the first set of credentials that match. 调用GetCredential方法时,它会比较统一资源标识符(URI)和提供的身份验证类型以及缓存中存储的身份验证类型,并返回匹配的第一组凭据。

I hope following would be another option that i took from code project url http://www.codeproject.com/Articles/49243/Handling-Cookies-with-Redirects-and-HttpWebRequest 我希望以下是我从代码项目中获取的另一个选项url 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;
}

Even though the OP is very old, I would nominate Crater's response as THE ANSWER. 虽然OP很老,但我会提名Crater的答案作为答案。 I went through similar gyrations, including creating a custom authentication module even though the web resource I was accessing only used Basic authentication. 我经历了类似的旋转,包括创建自定义身份验证模块,即使我访问的Web资源只使用了基本身份验证。 What I found was that only after I used a CredentialCache, instead of a simple NetworkCredential, did my authentication module get called after the redirect. 我发现只有在我使用CredentialCache而不是简单的NetworkCredential后,才会在重定向后调用我的身份验证模块。

Furthermore, I found that since the authentication I needed was Basic, by merely supplying the CredentialCache I did not need the custom authentication module at all -- the standard Basic module worked just fine. 此外,我发现由于我需要的身份验证是Basic,只需提供CredentialCache,我根本不需要自定义身份验证模块 - 标准的Basic模块工作得很好。

The following resource seemed to confirm this (in contrast to the .NET documentation reference mentioned in the OP): 以下资源似乎证实了这一点(与OP中提到的.NET文档参考相反):

https://blogs.msdn.microsoft.com/ncl/2009/05/05/custom-http-authentication-schemes/ https://blogs.msdn.microsoft.com/ncl/2009/05/05/custom-http-authentication-schemes/

What you need to do is likely a POST request. 您需要做的可能是POST请求。 You are posting variables to authenticate, thus you need to use the POST action. 您要发布变量以进行身份​​验证,因此您需要使用POST操作。

See this post for more information: Login to website, via C# 有关更多信息,请参阅此帖子: 通过C#登录网站

Auto redirect shouldn't get in the way of this post request. 自动重定向不应妨碍此帖子请求。 I'd recommend installing Fiddler and logging in manually, and then watching what happens. 我建议安装Fiddler并手动登录,然后观察会发生什么。

*Keep in mind, when sending a POST request, if there is a login form, you are sending the POST request to the action='/some-url-or-whatever.php' tag in the form. *请记住,在发送POST请求时,如果有登录表单,您将POST请求发送到表单中的action='/some-url-or-whatever.php'标记。 POST the data to that, and you should be able to log in just fine. POST数据到这一点,你应该能够登录就好了。

Let me know if this helps. 如果这有帮助,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM