2013-06-15 16 views
20

Sono novizio per Android e questo è il mio primo progetto su Android. Sto lottando con il problema di "autenticazione" per più di un giorno. Ho provato diverse opzioni ma nessuna ha funzionato.java.io.IOException: Nessun problema di autenticazione trovato

Fondamentalmente, voglio chiamare un'API REST e ottenere risposta. Sono sicuro che non ci sono problemi in API poiché utilizzo lo stesso in un'altra applicazione iOS.

Ho passato l'intestazione di autorizzazione ma ancora l'autenticazione nessun messaggio trovato è indicato. Ho trovato poche domande sullo stackoverflow relative a questo, ma alcune di esse non hanno funzionato e alcune non hanno senso per me.

Ricevo il codice di stato 401. So che questo significa che nessuna autenticazione è passata o se è passata, quindi sono sbagliate. Qui, sono sicuro che i miei passati sono corretti.

Qui di seguito è il mio codice:

try { 
    url = new URL(baseUrl); 
} 
catch (MalformedURLException me) { 
    Log.e(TAG, "URL could not be parsed. URL : " + baseUrl + ". Line : " + getLineNumber(), me); 
    me.printStackTrace(); 
} 

try { 
    urlConnection = (HttpURLConnection) url.openConnection(); 
    urlConnection.setRequestMethod(method); 
    urlConnection.setConnectTimeout(TIMEOUT * 1000); 
    urlConnection.setChunkedStreamingMode(0); 

    // Set HTTP headers     
    String authString = "username:password"; 
    String base64Auth = Base64.encodeToString(authString.getBytes(), Base64.DEFAULT); 
    urlConnection.setRequestProperty("Authorization", "Basic " + base64Auth); 
    urlConnection.setRequestProperty("Accept", "application/json"); 
    urlConnection.setRequestProperty("Content-type", "application/json"); 

    if (method.equals("POST") || method.equals("PUT")) { 
     // Set to true when posting data 
     urlConnection.setDoOutput(true); 

     // Write data to post to connection output stream 
     OutputStream out = urlConnection.getOutputStream(); 
     out.write(postParameters.getBytes("UTF-8")); 
    } 

    try { 
     // Get response 
     in = new BufferedInputStream(urlConnection.getInputStream()); 
    } 
    catch (IOException e) { 
     Log.e(TAG, "Exception in getting connection input stream. in : " + in); 
        e.printStackTrace(); 
    } 

    // Read the input stream that has response 
    statusCode = urlConnection.getResponseCode(); 
    Log.d(TAG, "Status code : " + statusCode); 
} 
catch (ProtocolException pe) { 
    pe.printStackTrace(); 
} 
catch (IllegalStateException ie) { 
    ie.printStackTrace(); 
} 
catch (IOException e) { 
    e.printStackTrace(); 
} 
finally { 
    urlConnection.disconnect(); 
} 


Guardate screenshot di logcat:

logcat

Qualsiasi aiuto sarebbe apprezzato. Grazie.

+0

String authString = "nomeutente: password"; questo "nome utente: password" dovrebbe essere uguale alle loro stringhe intendo nel modello degli sviluppatori del sito web. per esempio: possono usare Loginid: password del genere. – manivannan

+0

@Akash hai trovato una soluzione a questo? – AsafK

+0

@AsafK Il motivo era che HttpUrlConnection generava un'eccezione per il codice di stato 400 e successivi. Dobbiamo gestire questa eccezione. Nel mio caso, ho finito per utilizzare HttpClient anziché HttpUrlConnetion per la gestione di tutti i codici di stato. – Geek

risposta

1

Quale versione di Android stai testando?

Ho avuto difficoltà con l'autenticatore di Android durante alcuni lavori di sviluppo su Gingerbread (non so se si comporta in modo diverso nelle versioni successive di Android). Ho usato Fiddler2 per esaminare il traffico HTTP tra la mia app e il server, scoprendo che l'autenticatore non ha inviato la stringa di autenticazione per ogni richiesta HTTP. Ne avevo bisogno.

Invece, ho fatto ricorso a questo:

urlConnection.setRequestProperty("Authorization", "Basic " + Base64.encodeToString("userid:pwd".getBytes(), Base64.NO_WRAP)); 

Si tratta di un cut-e-incolla dal mio codice. Si noti che urlConnection è un oggetto HttpURLConnection.

+0

Ho provato questo. Ma non ha funzionato. Anche io ho provato a utilizzare diversi flag base64 come 'URL_SAFE',' NO_WRAP', 'DEFAULT'. Ho anche provato "URL_SAFE | NO_WRAP'". – Geek

+0

Ho controllato che Fiddler2 è per Windows. Esiste per MAC? – Geek

+0

La versione per Android è ICS. – Geek

45

Questo errore si verifica perché il server invia un 401 (non autorizzato) ma non fornisce un'intestazione WWW-Authenticate che è un suggerimento per il client su cosa fare dopo. L'intestazione WWW-Authenticate indica al client il tipo di autenticazione necessaria (Basic o Digest). Questo probabilmente non è molto utile nei client HTTP senza testa, ma è così che il HTTP 1.1 RFC is defined. L'errore si verifica perché la lib prova ad analizzare l'intestazione WWW-Authenticate ma non ci riesce.

Dal RFC:

(...) La risposta deve includere un campo di intestazione WWW-Authenticate (sezione 14.47) che contiene una sfida applicabile alla risorsa richiesta (...)

.

possibili soluzioni, se si può modificare il server:

  • Aggiungi un falso "WWW-Authenticate" intestazione come: WWW-Authenticate: Basic realm="fake". Questa è una semplice soluzione alternativa, non una soluzione, ma dovrebbe funzionare e il client http è soddisfatto (see here a discussion of what you can put in the header).Ma attenzione che alcuni client http possono ritentare automaticamente la richiesta risultante in più richieste (ad esempio, incrementa il numero di login errato troppo spesso). Ciò è stato osservato con il client http iOS.
  • Come proposto dalla loudvchar in this blog per evitare reazioni automatiche per la sfida come un form di login pop-up in un browser, è possibile utilizzare un metodo di autenticazione non standard in questo modo: WWW-Authenticate: xBasic realm="fake". Il punto importante è che il realm deve essere incluso.
  • Utilizzare il codice di stato HTTP 403 anziché 401. È semantica non è la stessa cosa e di solito quando si lavora con login 401 è una risposta corretta (see here for a detailed discussion) ma la soluzione più sicura in termini di compatibilità.

soluzioni possibili se può non modificare il server:

  • Come @ErikZ ha scritto nel suo post si può usare una prova & cattura

    HttpURLConnection connection = ...; 
    try { 
        // Will throw IOException if server responds with 401. 
        connection.getResponseCode(); 
    } catch (IOException e) { 
        // Will return 401, because now connection has the correct internal state. 
        int responsecode = connection.getResponseCode(); 
    } 
    
  • utilizzare diversi client http come OkHttp

+0

Cool man, giuro di aver visto un comportamento diverso, comunque appena testato cosa stai dicendo ed è corretto +1 ... –

+0

Sto riscontrando questo problema su un dispositivo Android ma non su un altro, suppongo che alcuni OEM sovrascrivano la classe HttpUrlConnection? Ad ogni modo, questa correzione ha funzionato. – ashishduh

+0

Sei un dio tra gli uomini. –

1

Ho avuto lo stesso problema su dispositivi con Android pre-KitKat, ma stavo usando la libreria Volley quindi la correzione lato client fornita da @ for3st non funzionava per me, ho dovuto regolarla per Volley, qui è, spero che aiuta qualcuno alle prese con questo problema:

HurlStack hurlStack = new HurlStack() { 
      @Override 
      public HttpResponse performRequest(final Request<?> request, final Map<String, String> additionalHeaders) throws IOException, AuthFailureError { 
       try { 
        return super.performRequest(request, additionalHeaders); 
       } catch (IOException e) { 
        return new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), 401, e.getMessage()); 
       } 
      } 
     }; 

Volley.newRequestQueue(context.getApplicationContext(), hurlStack); 

In questo modo viene restituito un errore di 401 e la vostra politica di tentativi può fare il suo lavoro (ad esempio, richiesta token ... ecc ...). Sebbene IOException possa essere causato da qualche altro problema, ad eccezione di un 401, è possibile scegliere di analizzare il messaggio di eccezione per la parola chiave Autorizzazione e restituire un codice di risposta diverso per gli altri.

1

Aveva lo stesso problema su alcuni vecchi dispositivi (Huawei Y330-U11 per esempio). Il modo corretto per risolverlo è quello di risolvere il problema lato server come menzionato nella risposta più popolare.

Tuttavia, è davvero deludente che il problema si verifichi solo su alcuni dispositivi. E credo che ciò avvenga a causa di diverse implementazioni di "UrlConnection". Diverse versioni di Android: diverse implementazioni "UrlConnection".

Quindi, si consiglia di risolvere il problema utilizzando lo stesso "UrlConnection" ovunque. Prova a usare okhttp e okhttp-urlconnection.

Ecco il modo per aggiungere quelle librerie per il vostro costruire Gradle:

compile 'com.squareup.okhttp:okhttp:2.5.0' 
compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0' 

E 'risolto il problema per me su quei dispositivi obsoleti. (Ho dovuto usare OkClient per Retrofit RestAdapter)

P.S. Gli ultimi androidi al momento della scrittura utilizzano internamente la vecchia versione della libreria OKHTTP come implemetazione "UrlConnection" (con nomi di pacchetti aggiornati), quindi sembra essere una cosa abbastanza solida

Problemi correlati