2011-10-18 4 views
11

Sto utilizzando un HttpsUrlConnection con l'autenticazione di base utilizzando un Authenticator e impostando un Authenticator oggetto predefinito in questo modo:Android: HttpsURLConnection con Authenticator per itera Autenticazione di base per sempre quando la password è sbagliata (su 401 risposta)

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

Quando accedo al mio servizio web, la connessione chiama il mio metodo getPasswordAuthentication() per ottenere le credenziali e inviarlo al server web. Funziona bene finché la password è corretta. :)

Tuttavia, è appena successo che qualcuno ha cambiato la password di autenticazione di base sul server Web e quindi la mia richiesta non è tornata.

Ho eseguito il debug e ciò che accade è che la mia chiamata a getInputStream() non restituisce mai. Lo HttpsUrlConnection ottiene una risposta 401 e reagisce a questo internamente ottenendo di nuovo le stesse credenziali. Ma dato che ho fornito solo un utente e una password, questo fallirà di nuovo (e di nuovo ...).

Quindi la mia domanda è: come posso evitare questo e dove c'è un gancio per rispondere a una password errata (risp. Una risposta 401) in modo da poter mostrare un messaggio di errore appropriato e annullare la richiesta?

Ecco un estratto della traccia dello stack dei metodi che vengono chiamati la ripetuta su 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

possibile duplicato di [Android, HttpURLConnection e gestione delle credenziali cattivi] (http://stackoverflow.com/questions/7061211/android-httpurlconnection-and-handling- cattive credenziali) – yanchenko

risposta

5

Ho risolto questo problema astraendo richiesta logica/risposta via in una classe MyRequest. Ciò mi consente di avere una variabile con ambito di richiesta che può dire al mio Authenticator se deve fare una richiesta usando un nome utente e una password specificati, o se dovrebbe smettere di riprovare (restituendo null). Sembra un po 'come la seguente (in considerazione questo pseudocodice)

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

      ... 

    } 
} 
+0

esattamente! grazie per averlo indicato! è come nella risposta che ha chiuso http://code.google.com/p/android/issues/detail?id=7058 all'autenticatore che chiede all'utente un * nuovo * insieme di credenziali perché quelle fornite in precedenza non ha funzionato Se l'autenticatore utilizza solo credenziali preimpostate, deve tenerne traccia del precedente tentativo fallito. – Maks

3

Vorrei sapere la risposta giusta a questo, perché ho incontrato lo stesso identico problema. Non sono riuscito a trovare un modo per gestire l'errore di autenticazione o persino a ricevere una notifica al riguardo.

Ho dovuto utilizzare invece 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())); 
+0

Sembra essere una buona alternativa però. Non ho cambiato nulla nel mio codice. Mi assicuro solo che nessuno cambi la password senza avvisarmi ... :-) – Jens