Android: HttpsUrlConnection с аутентификатором для базовой проверки подлинности итерации навсегда, когда пароль неверен (на ответ 401)
Я использую HttpsUrlConnection
с базовой аутентификацией, используя Authenticator
и устанавливая объект Authenticator
по умолчанию:
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user", "userpass"
.toCharArray());
}
});
Когда я обращаюсь к своему веб-сервису, соединение вызывает мой метод 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
Ответы
Ответ 1
Я решил эту проблему, абстрагировав логику запроса/ответа от класса MyRequest
. Это позволяет мне иметь переменную с областью запроса, которая может сообщить моему Authenticator
, должен ли он делать запрос с использованием указанного имени пользователя и пароля или он должен прекратить повторную попытку (возвращая 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());
...
}
}
Ответ 2
Хотел бы я знать правильный ответ на этот вопрос, потому что я столкнулся с той же проблемой. Я не мог найти способ справиться с ошибкой аутентификации или даже получить уведомление об этом.
В итоге мне пришлось использовать 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()));