2012-03-02 20 views
12

He estado utilizando HTTPClient versión 4.1.2 para tratar de acceder a un REST a través de HTTP API que requiere autenticación básica. Aquí está el código de cliente:¿HTTPClient envía dos solicitudes cuando se usa autenticación básica?

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

Cuando construyo una solicitud POST, así:

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

que veo en Charles Proxy que hay dos peticiones que se envían. Uno sin el encabezado Authorization: Basic ... y otro con. El primero falla con un 401, como era de esperar, pero el segundo pasa muy bien con un 201.

¿Alguien sabe por qué sucede esto? ¡Gracias!

EDIT:

Quiero dejar en claro que ya he mirado this question, pero como se puede ver que establezca el AuthScope la misma manera y no resolvió mi problema. Además, estoy creando un nuevo HttpClient cada vez que hice una solicitud (aunque utilizo el mismo ConnectionManager), pero incluso si uso el mismo HttpClient para múltiples solicitudes, el problema aún persiste.

EDIT 2:

Así que parece que lo @LastCoder estaba sugiriendo es la manera de hacerlo. Vea this answer a otra pregunta. El problema proviene de mi falta de conocimiento sobre las especificaciones HTTP. Lo que estoy buscando hacer es llamar "autenticación preventiva" y HttpClientdocs mention it here. Afortunadamente, la respuesta vinculada a lo anterior es una manera mucho más corta y limpia de hacerlo.

+1

Noté que sucedía lo mismo cuando se usa soap-ui aunque se especificaron las credenciales. – Harindaka

+0

Me pregunto si esto es realmente un comportamiento normal. El cliente realiza una solicitud http sin asumir ninguna autenticación y luego se le informa (a través del 401) que se necesita autenticación básica. En teoría, la autenticación básica se puede realizar de forma preventiva, pero otros esquemas de autenticación (por ejemplo, resumen) necesitan negociación adicional – seand

+0

@se y usted sabe que realmente lo consideré, pero no sé si eso está integrado en el protocolo HTTP o algo así. – daveslab

Respuesta

10

En lugar de utilizar .setCredentials() ¿por qué no simplemente codificar USUARIO: CONTRASEÑA y añadir la cabecera de autenticación con .addHeader()

+0

Podría hacer eso, sin duda, y probaré para ver si eso hace la diferencia, pero según el código de ejemplo (http://bit.ly/wEsEhY) en el repositorio 'HttpClient', esa es la forma en que debería hacerlo eso. – daveslab

+7

@daveslab - Es parte de la especificación del cliente http solicitar primero el recurso de forma anónima y responder al 401 con el encabezado Autorización. Si no fuera así, los clientes estarían enviando spam a los servidores web con credenciales de encabezado de autorización que el servidor web ni siquiera necesita. Es solo la mejor práctica básica de seguridad. –

+0

Es una solución de fuerza bruta, pero haría más difícil cambiar los protocolos si fuera necesario (por ejemplo, si el servidor cambió para usar la autenticación de resumen) – seand

2

Esto significa que el punto final de servidor/objetivo es la creación de una nueva sesión para cada solicitud de cliente. Esto obliga a que todas sus solicitudes pasen por un apretón de manos, lo que significa que los clientes primero hacen la llamada y se dan cuenta de que necesitan autorización, luego la siguen con la autorización. Lo que debe hacer es enviar la autorización de forma preventiva de la siguiente manera:

httpClient.getParams(). SetAuthenticationPreemptive (true);

Para comprender el proceso, puede registrar los encabezados de las solicitudes de sus clientes, para que tenga una idea de lo que está enviando y recibiendo su cliente: Vea si esto funciona.

Cuestiones relacionadas