2012-11-28 16 views
5

Nella mia app faccio chiamate HTTP a un servizio web su HTTPS. Il mio desiderio è di progettare il mio cliente in modo tale da chiedere all'utente solo il nome utente e la password quando c'è una richiesta di autenticazione. Voglio essere reattivo, non preventivo. A causa della natura della mia app, ci sono alcuni casi in cui non è necessario autenticarsi.Come rispondere alle sfide di autenticazione HTTP in Android

In iOS, questo processo è reso molto semplice tramite il NSURLConnectionDelegateProtocol, che è implementato nella versione iOS della mia app. Viene effettuata una connessione utilizzando questa classe e solo quando viene presentata una sfida la classe chiede al suo delegato le credenziali di autenticazione.

Come può essere fatto in Android? Utilizzando lo AuthenticationHandler? O forse lo Authenticator? In tal caso, potrebbe essere fornito un esempio o un tutorial?

Edit 1:

Uso della classe Authenticator (vedi la mia risposta qui sotto) sono ora in grado di rispondere alle sfide di autenticazione, ma attualmente solo con le credenziali hard-coded. Voglio chiedere all'utente un nome utente e una password. Secondo lo Android documentation, all'interno del metodo getPasswordAuthentication "si richiede di solito all'utente l'input richiesto".

Com'è possibile? Senza bloccare il thread dell'interfaccia utente, che so non può/non deve essere eseguito, come è possibile visualizzare una finestra di dialogo, attendere l'input dell'utente, quindi recuperare le credenziali immesse e restituirle, tutte all'interno di tale metodo?

Edit 2:

Mentre ci sono poche o nessuna esempi sull'uso della classe Authenticator, quello che ho potuto trovare suggerisce che richiede all'utente per l'input è impossibile all'interno di un singolo metodo, come getPasswordAuthentication. Potrebbe essere necessario ripristinare il client HTTP Apache ...

finale Edit:

sto ancora utilizzando HttpURLConnection, ma fare qualcosa sulla falsariga di ciò che Edward ha suggerito di seguito. Non sembra esserci alcuna classe configurabile per gestire le sfide di autenticazione e richiedere all'utente l'input, quindi lo faccio manualmente.

risposta

3

Invia la richiesta senza intestazioni di autenticazione. Se è richiesta l'autenticazione, la connessione fallirà con un errore 401. Lascia che questo errore risponda a qualsiasi codice abbia fatto la richiesta iniziale. Quel codice dovrebbe quindi mostrare una finestra di autenticazione all'utente. Ricordare il nome utente/password fornito dall'utente e riprovare la richiesta non riuscita con l'intestazione di autenticazione necessaria aggiunta alla richiesta.

Ricordare nome utente/password per il resto della sessione in modo da non dover continuare a chiedere all'utente.

Mi dispiace che non ho alcun codice di esempio; L'ho implementato in java.net, ma non ti servirà a niente se usi Apache.

Questo thread può aiutare: Http Basic Authentication in Java using HttpClient?

Edit:

ho implementato questo in java.net, ma era lavoro che ho fatto per il noleggio e non avere accesso al codice sorgente.Un problema è che java.net non ti consente di impostare l'autenticazione su base per connessione, ma invece di implementare un singolo autenticatore globale. Poiché la mia app comunicava solo con un sito Web specifico, non era un problema.

Quello che ho fatto è stato creare una sottoclasse di Authenticator che memorizza i dati del nome utente/password dall'utente. Il valore iniziale della cache era vuoto. C'è anche un "contatore dei tentativi". Quando viene chiamato l'autenticatore e non vi sono informazioni utente/password memorizzate nella cache, l'utente viene richiesto tramite una finestra di dialogo. Se i valori memorizzati nella cache sono presenti, vengono restituiti senza infastidire l'utente.

Se ci sono chiamate successive all'autenticatore, si presume che le informazioni utente/password non siano corrette e l'utente venga nuovamente richiesto. Se il contatore raggiunge dieci, l'autenticatore restituisce null (errore).

Il contatore viene ripristinato prima di ogni nuova connessione Internet.

Un autenticatore più intelligente dovrebbe prestare attenzione all'host e/o al dominio (stringa di richiesta) e memorizzare nella cache utente/password di conseguenza.

Non sono sicuro che tutto ciò ti sarà utile in un ambiente Android, poiché l'apertura di una finestra di dialogo potrebbe non essere un'opzione disponibile per l'autenticatore. Ma potrei sbagliarmi su questo; dipende dalla tua applicazione.

In un ambiente Android, è necessario eseguire le richieste http da un thread e quindi segnalare l'attività quando i dati sono arrivati. Se il tuo thread rileva un errore 401, segnalerebbe l'attività a quell'effetto, e quindi l'attività potrebbe apparire in una finestra di dialogo e rilanciare il thread. Il thread registrerebbe quindi un autenticatore banale che ha semplicemente restituito le informazioni utente/password. In alternativa, il thread potrebbe creare manualmente un'intestazione di autorizzazione, anche se è più lavoro.

+0

Sto anche tentando di utilizzare java.net, poiché sembra che sia l'opzione più supportata in futuro. Proverò ciò che hai suggerito. Hai mai provato a usare la classe Authenticator? – Groppe

+0

Vedere le mie modifiche sopra. –

+0

Grazie. Da quello che ho letto, l'apertura di una finestra di dialogo (quello che voglio fare) non è possibile all'interno del metodo getPasswordAuthentication dell'autenticatore, sfortunatamente. – Groppe

2

Per coloro che non sanno, ci sono due grandi di disponibile per l'utilizzo di API client HTTP in Android:

  • java.net HttpURLConnection
  • Una panoramica recente client

    • Apache HTTP di entrambi questi è dato in questo Android Developers Blog post.

      Ho scelto di utilizzare l'implementazione java.net, perché, citando il blog: "Le nuove applicazioni dovrebbero usare HttpURLConnection, è dove noi passeremo la nostra energia per il futuro" Inoltre, HttpURLConnection collegherà tramite SSL automaticamente se l'Url fornito è Https. Come ho affermato nel post originale, stavo cercando un'interfaccia all'interno dell'API che mi permettesse di gestire automaticamente le sfide di autenticazione, se necessario. Ho scoperto che la classe Authenticator fa quello che voglio.

      Ecco il codice che ho finora, e funziona:

      URL Url = new URL(url); 
      
      Authenticator.setDefault(new Authenticator() { 
          protected PasswordAuthentication getPasswordAuthentication() { 
           return (new PasswordAuthentication("username", "password".toCharArray())); 
          } 
      }); 
      
      connection = (HttpURLConnection) Url.openConnection(); 
      connection.setRequestProperty("Authorization", "Basic"); 
      
      content = new BufferedInputStream(connection.getInputStream()); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(content)); 
      String line; 
      while ((line = reader.readLine()) != null) { 
          stringBuilder.append(line); 
      } 
      

      La chiave (per me) per ottenere il metodo del Authenticator in realtà essere chiamato, era questa linea:

      connection.setRequestProperty("Authorization", "Basic"); 
      

      In caso contrario, la richiesta restituirà effettivamente una risposta di 200 (OK) e reindirizzerà a una pagina di accesso.

      Passaggio successivo: dal metodo getPasswordAuthentication in alto, richiedere all'utente nome utente e password e in qualche modo restituirlo. Se puoi aiutare con questo, pubblica una risposta!

    +0

    Heh; impara qualcosa di nuovo ogni giorno Avevo letto che java.net era considerato obsoleto, essendo stato sviluppato per JavaME e che tutti dovevano usare il client Apache. Ho usato java.net solo in situazioni in cui la libreria Apache non era disponibile. Immagino sia ora di tornare indietro. –

    +0

    Edward, mi sono appena imbattuto in una domanda che hai posto (http://stackoverflow.com/questions/6100989/java-how-to-launch-a-ui-dialog-from-another-thread-eg-for-authenticator) e la risposta che tu/Andrea ha fornito sembra essere in qualche modo sulla falsariga di quello che sto cercando di fare ora. Hai detto in un commento "Desidero che Java abbia la funzione di passaggio dei messaggi di Android." Visto che stiamo parlando di Android ora, come consiglieresti di farlo? – Groppe

    +0

    Bel lavoro ragazzi..Ho un complicato processo di autenticazione iOS e non avevo idea di come farlo in Android. Sono sorpreso che non ci siano più upvotes per entrambi. Devo memorizzare un/pw per passare un SSL e poi passare una richiesta di autenticazione di Windows, quindi questo post è utile per questo tipo di processo. – whyoz

    Problemi correlati