2012-03-02 4 views
12

Ho utilizzato HTTPClient versione 4.1.2 per provare ad accedere a un'API REST su HTTP che richiede l'autenticazione di base. Ecco il codice client:HTTPClient invia due richieste quando si utilizza l'autenticazione di base?

DefaultHttpClient httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager()); 
// Enable HTTP Basic Auth 
httpClient.getCredentialsProvider().setCredentials(
    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), 
    new UsernamePasswordCredentials(this.username, this.password)); 

HttpHost proxy = new HttpHost(this.proxyURI.getHost(), this.proxyURI.getPort()); 

httpClient.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, proxy); 

Quando costruisco una richiesta POST, in questo modo:

HttpPost request = new HttpPost("http://my/url"); 
request.addHeader(new BasicHeader("Content-type", "application/atom+xml; type=entry")); // required by vendor 
request.setEntity(new StringEntity("My content")); 

HttpResponse response = client.execute(request); 

vedo in Charles Proxy che ci sono due richieste di essere inviati. Uno senza l'intestazione Authorization: Basic ... e uno con esso. Il primo fallisce con un 401, come ci si aspetterebbe, ma il secondo va bene con un 201.

Qualcuno sa perché questo accade? Grazie!

EDIT:

Vorrei chiarire che ho già guardato this question, ma come potete vedere ho impostare la AuthScope allo stesso modo e che non ha risolto il mio problema. Inoltre, sto creando un nuovo HttpClient ogni volta che ho fatto una richiesta (anche se io uso lo stesso ConnectionManager), ma anche se io uso lo stesso HttpClient per più richieste, il problema persiste ancora.

EDIT 2:

Quindi sembra che quello che stava suggerendo @LastCoder è il modo per farlo. Vedere this answer per un'altra domanda. Il problema deriva dalla mia scarsa conoscenza delle specifiche HTTP. Quello che sto cercando di fare è chiamato "autenticazione preventiva" e lo HttpClientdocs mention it here. Per fortuna, la risposta di cui sopra è un modo molto più breve e più pulito per farlo.

+1

Ho notato la stessa cosa che si verificava quando si utilizzava soap-ui anche se le credenziali erano state specificate. – Harindaka

+0

Mi chiedo se questo comportamento sia normale. Il client effettua una richiesta http non assumendo alcuna autenticazione e viene quindi detto (tramite il 401) che è necessaria l'autenticazione di base. In teoria, l'autenticazione di base potrebbe essere effettuata in modo preventivo, ma altri schemi di autenticazione (ad esempio digest) richiedono una negoziazione aggiuntiva – seand

+0

@seand Si sa che in realtà l'ho considerato, ma non so se questo è integrato nel protocollo HTTP o qualcosa del genere. – daveslab

risposta

10

Invece di utilizzare .setCredentials() perché non solo codificare username: password e aggiungere l'intestazione di autenticazione con .addHeader()

+0

Potrei farlo, certamente, e testerò per vedere se questo fa la differenza, ma secondo il codice di esempio (http://bit.ly/wEsEhY) nel repository 'HttpClient', questo è il modo in cui dovrei fare esso. – daveslab

+7

@daveslab - Fa parte delle specifiche del client http per richiedere la risorsa anonimamente prima e rispondere al 401 con l'intestazione Autorizzazione. Se non lo fossero i client invaderebbero i server Web con credenziali di intestazione dell'autorizzazione che il server Web non ha nemmeno bisogno. Sono solo le migliori pratiche di sicurezza di base. –

+0

È una soluzione a forza bruta ma renderebbe più difficile cambiare i protocolli, se necessario (ad esempio, se il server è stato modificato per utilizzare auth digest) – seand

2

Ciò significa che l'endpoint del server/target è la creazione di una nuova sessione per ogni richiesta del cliente. Questo costringe ogni tua richiesta a passare attraverso una stretta di mano, il che significa che i client prima fanno la chiamata e si rendono conto che ha bisogno di autorizzazione, quindi segue con l'autorizzazione. Quello che devi fare è inviare l'autorizzazione preventivamente come segue:

httpClient.getParams(). SetAuthenticationPreemptive (true);

Giusto per capire il processo è possibile registrare le intestazioni delle richieste dei clienti, per darti un'idea di ciò che il tuo cliente sta inviando e ricevendo: Verifica se funziona.