Android – Configuración de Retrofit / Apache HttpClient para Digest Auth
Estoy trabajando en un proyecto de Android y tratando de conseguir que Digest Authentication funcione con Retrofit. Estoy un poco sorprendido Retrofit no lo apoya nativamente (o más exactamente, que OkHttp no lo soporta), pero no hay punto de quejarse supongo.
He cruzado a través de unos cuantos hilos aquí y parece que la solución correcta es integrar el Apache HttpClient (que admite nativamente Digest Auth) con Retrofit. Esto requiere envuelto el HttpClient con una implementación retrofit.client.Client. Los valores entrantes de adaptación tienen que ser analizados y construidos en una nueva respuesta HttpClient que luego se envía de nuevo a Retrofit para que se procese normalmente. Crédito a Jason Tu y su ejemplo en: https://gist.github.com/nucleartide/24628083decb65a4562c
- ¿Cómo usar Retrofit y SimpleXML juntos para descargar y analizar un archivo XML de un sitio?
- El tipo de retorno observable debe parametrizarse como Observable <Foo> o Observable <? Se extiende Foo>
- Cargue archivos en el cubo AWS S3 usando OkHttp o Retrofit
- Autentificación JWT de la firma de la firma del decodin del error
- Uso de subscribeOn con Retrofit
El problema es que no está funcionando. Estoy recibiendo un 401 desautorizado cada vez y no está claro para mí por qué. Aquí está mi Cliente impl:
public class AuthClientRedirector implements Client { private final CloseableHttpClient delegate; public AuthClientRedirector(String user, String pass, String hostname, String scope) { Credentials credentials = new UsernamePasswordCredentials(user, pass); AuthScope authScope = new AuthScope(hostname, 443, scope); CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(authScope, credentials); delegate = HttpClientBuilder.create() .setDefaultCredentialsProvider(credentialsProvider) .build(); } @Override public Response execute(Request request) { // // We're getting a Retrofit request, but we need to execute an Apache // HttpUriRequest instead. Use the info in the Retrofit request to create // an Apache HttpUriRequest. // String method = request.getMethod(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); if (request.getBody() != null) { try { request.getBody().writeTo(bos); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } String body = new String(bos.toByteArray()); HttpUriRequest wrappedRequest; switch (method) { case "GET": wrappedRequest = new HttpGet(request.getUrl()); break; case "POST": wrappedRequest = new HttpPost(request.getUrl()); wrappedRequest.addHeader("Content-Type", "application/xml"); try { ((HttpPost) wrappedRequest).setEntity(new StringEntity(body)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case "PUT": wrappedRequest = new HttpPut(request.getUrl()); wrappedRequest.addHeader("Content-Type", "application/xml"); try { ((HttpPut) wrappedRequest).setEntity(new StringEntity(body)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case "DELETE": wrappedRequest = new HttpDelete(request.getUrl()); break; default: throw new AssertionError("HTTP operation not supported."); } CloseableHttpResponse apacheResponse = null; try { apacheResponse = delegate.execute(wrappedRequest); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(apacheResponse!=null){ // Perform the HTTP request. CloseableHttpResponse response = null; try { response = delegate.execute(wrappedRequest); // Return a Retrofit response. List<Header> retrofitHeaders = toRetrofitHeaders( response.getAllHeaders()); TypedByteArray responseBody; if (response.getEntity() != null) { responseBody = new TypedByteArray("", toByteArray(response.getEntity())); } else { responseBody = new TypedByteArray("", new byte[0]); } System.out.println("this is the response"); System.out.println(new String(responseBody.getBytes())); return new retrofit.client.Response(request.getUrl(), response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), retrofitHeaders, responseBody); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (response != null) { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //failed to return a new retrofit Client return null; } private List<Header> toRetrofitHeaders(org.apache.http.Header[] headers) { List<Header> retrofitHeaders = new ArrayList<>(); for (org.apache.http.Header header : headers) { retrofitHeaders.add(new Header(header.getName(), header.getValue())); } return retrofitHeaders; } private byte[] toByteArray(HttpEntity entity) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); entity.writeTo(bos); return bos.toByteArray(); }
}
Mi configuración de reacondicionamiento tiene este aspecto:
Public final RestAdapter configureService () {
AuthClientRedirector digestAuthMgr = new AuthClientRedirector(username,password,"myhostname","public"); RestAdapter.Builder builder = new RestAdapter.Builder() .setEndpoint("http://myhostname:8003/endpoint") .setLogLevel(RestAdapter.LogLevel.FULL) .setClient(digestAuthMgr); return builder.build(); }
Estoy stumped por qué estoy constantemente conseguir 401s volver del servidor. He caminado a través del proceso de construcción de la respuesta y se ve limpio para mí, así que estoy pensando que estoy perdiendo algo fundamental. Las credenciales son buenas y las he verificado fuera de la aplicación. ¿Alguien caminó este paseo antes?
- Retrofit: ¿Cómo especificar parámetros separados por comas en la solicitud?
- Java.lang.NoClassDefFoundError: Resolución fallida de: Lretrofit2 / GsonConverterFactory;
- ¿Cómo aumentar el tiempo de espera para las solicitudes de reacondicionamiento en robospice android?
- Subir datos de imagen de varias partes en JSON con Retrofit?
- ¿Cómo pasar el enum personalizado en @Query a través de Retrofit?
- Patrón de repositorio con SqlBrite / SqlDelight (base de datos sin conexión) y Retrofit (solicitud Http)
- HTTP GET con el cuerpo de la solicitud RETROFIT
- ¿Cómo utilizo el convertidor Gson en RetroFit?
Está utilizando el número de puerto 443 para la autenticación.
AuthScope authScope = new AuthScope(hostname, 443, scope);
Pero, parece que su número de puerto real es 8003 .
RestAdapter.Builder builder = new RestAdapter.Builder() .setEndpoint("http://myhostname:8003/endpoint")
Entonces, ¿qué tal usar el número de puerto 8003 para la autenticación como a continuación?
AuthScope authScope = new AuthScope(hostname, 8003, scope);
- Android TimePicker Botón AM / PM que no invoca onTimeChanged
- Detección de lanzamientos de actividades de Android