Android:当密码错误时,带有用于基本身份验证的身份验证器的 HttpsUrlConnection 会永远迭代(在 401 响应上)

发布于 2024-12-10 16:54:24 字数 1570 浏览 0 评论 0原文

我使用 HttpsUrlConnection 进行基本身份验证,方法是使用 Authenticator 并设置默认 Authenticator 对象,如下所示:

Authenticator.setDefault(new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("user", "userpass"
            .toCharArray());
    }
});

当我访问我的 Web 服务时连接调用我的 getPasswordAuthentication() 方法来获取凭据并将其发送到网络服务器。只要密码正确,就可以正常工作。 :)

但是,恰巧有人更改了网络服务器上的基本身份验证密码,然后我的请求没有返回。

我对其进行了调试,结果是我对 getInputStream() 的调用永远不会返回。 HttpsUrlConnection 确实收到了 401 响应,并通过再次获取相同的凭据来对此做出内部反应。但由于我只提供了一个用户和密码,这将再次失败(一次又一次......)。

所以我的问题是:我怎样才能防止这种情况发生,哪里有一个钩子可以对错误的密码(分别是 401 响应)做出反应,以便我可以显示适当的错误消息并取消请求?

以下是在 HttpsUrlConnection 上重复调用的方法的堆栈跟踪摘录:

1: MyOwnHttpConnection$3.getPasswordAuthentication() line: 99   
2: Authenticator.requestPasswordAuthentication(InetAddress, int, String, String, String) line: 162  
3: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).getAuthorizationCredentials(String) line: 1205 
4: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).processAuthHeader(String, String) line: 1178   
5: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).processResponseHeaders() line: 1118    
6: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).retrieveResponse() line: 1044  
7: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).getInputStream() line: 523 
8: HttpsURLConnectionImpl.getInputStream() line: 283    

I am using an HttpsUrlConnection with Basic Authentication by using an Authenticator and setting a default Authenticator object like this:

Authenticator.setDefault(new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("user", "userpass"
            .toCharArray());
    }
});

When I access my web-service the connection calls my getPasswordAuthentication() method to get the credentials and sends this to the web-server. This works allright as long as the password is correct. :)

However, it just happened that someone changed the basic authentication password on the web-server and then my request did not return.

I debugged it and what happens is that my call to getInputStream() never returns. The HttpsUrlConnection does get a 401 response and reacts to this internally by getting the same credentials again. But since I only provided one user and password this will fail again (and again...).

So my question is: How can I prevent this and where is there a hook to react to a wrong password (resp. a 401 response) so I can show an appropriate error message and cancel the request?

Here is an extract of the stack trace of the methods that are called repeatingly on HttpsUrlConnection:

1: MyOwnHttpConnection$3.getPasswordAuthentication() line: 99   
2: Authenticator.requestPasswordAuthentication(InetAddress, int, String, String, String) line: 162  
3: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).getAuthorizationCredentials(String) line: 1205 
4: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).processAuthHeader(String, String) line: 1178   
5: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).processResponseHeaders() line: 1118    
6: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).retrieveResponse() line: 1044  
7: HttpsURLConnectionImpl$HttpsEngine(HttpURLConnectionImpl).getInputStream() line: 523 
8: HttpsURLConnectionImpl.getInputStream() line: 283    

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

客…行舟 2024-12-17 16:54:24

我通过将请求/响应逻辑抽象到 MyRequest 类中解决了这个问题。这允许我拥有一个请求范围的变量,它可以告诉我的身份验证器是否应该使用指定的用户名和密码发出请求,或者是否应该停止重试(通过返回 null)代码>)。它看起来有点像下面这样(考虑这个伪代码)

public class MyRequest
{
    private boolean alreadyTriedAuthenticating = false;
    private URL url;

    ...

    public void send()
    {
        HttpUrlConnection connection = (HttpUrlConnection) url.openConnection();
        Authenticator.setDefault(new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                if (!alreadyTriedAuthenticating)
                {
                    alreadyTriedAuthenticating = true;
                    return new PasswordAuthentication(username, password.toCharArray());
                }
                else
                {
                    return null;
                }
            }
            InputStream in = new BufferedInputStream(connection.getInputStream());

            ...

    }
}

I solved this problem by abstracting request/response logic away into a MyRequest class. This allows me to have a request-scoped variable that can tell my Authenticator whether it should make a request using a specified username and password, or whether it should stop retrying (by returning null). It looks somewhat like the following (consider this pseudocode)

public class MyRequest
{
    private boolean alreadyTriedAuthenticating = false;
    private URL url;

    ...

    public void send()
    {
        HttpUrlConnection connection = (HttpUrlConnection) url.openConnection();
        Authenticator.setDefault(new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                if (!alreadyTriedAuthenticating)
                {
                    alreadyTriedAuthenticating = true;
                    return new PasswordAuthentication(username, password.toCharArray());
                }
                else
                {
                    return null;
                }
            }
            InputStream in = new BufferedInputStream(connection.getInputStream());

            ...

    }
}
So尛奶瓶 2024-12-17 16:54:24

我希望我知道正确的答案,因为我遇到了完全相同的问题。我找不到处理身份验证错误的方法,甚至找不到有关它的通知。

我最终不得不使用 HttpClient 来代替。

HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(loginUrl);
String authString = (userName+":"+password);
get.addHeader("Authorization", "Basic " + 
    Base64.encodeToString(authString.getBytes(),Base64.NO_WRAP));
HttpResponse response = client.execute(get);

BufferedReader r = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

I wish I knew the proper answer to this, because I ran into the exact same problem. I couldn't find a way to handle the authentication error, or even get notified about it.

I ended up having to use HttpClient instead.

HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(loginUrl);
String authString = (userName+":"+password);
get.addHeader("Authorization", "Basic " + 
    Base64.encodeToString(authString.getBytes(),Base64.NO_WRAP));
HttpResponse response = client.execute(get);

BufferedReader r = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文