studio okhttpclient library android okhttp

okhttpclient - Android OkHttp con autenticación básica



okhttp vs retrofit (9)

Estoy usando la biblioteca OkHttp para un nuevo proyecto y estoy impresionado con su facilidad de uso. Ahora necesito usar Autenticación básica. Desafortunadamente, hay una escasez de código de muestra de trabajo. Estoy buscando un ejemplo de cómo pasar credenciales de nombre de usuario / contraseña al OkAuthenticator cuando se encuentra un encabezado HTTP 401. Vi esta respuesta:

Retrofit solicitud POST con autenticación HTTP básica: "No se puede reintentar el cuerpo HTTP transmitido"

pero no me llevó demasiado lejos. Las muestras en el repositorio OkHttp github tampoco tenían una muestra basada en autenticación. ¿Alguien tiene una idea u otra muestra de código para que me apunte en la dirección correcta? ¡Gracias por tu ayuda!


Alguien pidió una versión de Kotlin del interceptor. Aquí es lo que se me ocurrió y funciona genial:

val client = OkHttpClient().newBuilder().addInterceptor { chain -> val originalRequest = chain.request() val builder = originalRequest.newBuilder() .header("Authorization", Credentials.basic("ausername", "apassword")) val newRequest = builder.build() chain.proceed(newRequest) }.build()


Aquí está el código actualizado:

client.setAuthenticator(new Authenticator() { @Override public Request authenticate(Proxy proxy, Response response) throws IOException { String credential = Credentials.basic("scott", "tiger"); return response.request().newBuilder().header("Authorization", credential).build(); } @Override public Request authenticateProxy(Proxy proxy, Response response) throws IOException { return null; } })


Código de actualización para okhttp3:

import okhttp3.Authenticator; import okhttp3.Credentials; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.Route; public class NetworkUtil { private final OkHttpClient.Builder client; { client = new OkHttpClient.Builder(); client.authenticator(new Authenticator() { @Override public Request authenticate(Route route, Response response) throws IOException { if (responseCount(response) >= 3) { return null; // If we''ve failed 3 times, give up. - in real life, never give up!! } String credential = Credentials.basic("name", "password"); return response.request().newBuilder().header("Authorization", credential).build(); } }); client.connectTimeout(10, TimeUnit.SECONDS); client.writeTimeout(10, TimeUnit.SECONDS); client.readTimeout(30, TimeUnit.SECONDS); } private int responseCount(Response response) { int result = 1; while ((response = response.priorResponse()) != null) { result++; } return result; } }


Como lo señaló @agamov:

La solución antes mencionada tiene un inconveniente: httpClient agrega encabezados de autorización solo después de recibir la respuesta 401

@agamov propuso entonces agregar "manualmente" encabezados de autenticación a cada solicitud, pero hay una mejor solución: usar un Interceptor :

import java.io.IOException; import okhttp3.Credentials; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; public class BasicAuthInterceptor implements Interceptor { private String credentials; public BasicAuthInterceptor(String user, String password) { this.credentials = Credentials.basic(user, password); } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Request authenticatedRequest = request.newBuilder() .header("Authorization", credentials).build(); return chain.proceed(authenticatedRequest); } }

Luego, simplemente agregue el interceptor a un cliente OkHttp que utilizará para realizar todas sus solicitudes autenticadas:

OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new BasicAuthInterceptor(username, password)) .build();


Intenta usar OkAuthenticator :

client.setAuthenticator(new OkAuthenticator() { @Override public Credential authenticate( Proxy proxy, URL url, List<Challenge> challenges) throws IOException { return Credential.basic("scott", "tiger"); } @Override public Credential authenticateProxy( Proxy proxy, URL url, List<Challenge> challenges) throws IOException { return null; } });

ACTUALIZAR:

Renombrado a Authenticator


La solución antes mencionada tiene un inconveniente: httpClient agrega encabezados de autorización solo después de recibir la respuesta 401. Así es como se veía mi comunicación con api-server:

Si necesita usar la autenticación básica para cada solicitud, mejor agregue sus encabezados de autenticación a cada solicitud o use un método de envoltura como este:

private Request addBasicAuthHeaders(Request request) { final String login = "your_login"; final String password = "p@s$w0rd"; String credential = Credentials.basic(login, password); return request.newBuilder().header("Authorization", credential).build(); }


Me di cuenta en Android con algunas API de servidor como django que deberías agregar una palabra en token

Request request = new Request.Builder() .url(theUrl) .header("Authorization", "Token 6utt8gglitylhylhlfkghriyiuy4fv76876d68") .build();

, donde esa palabra problemática es ese "Token". En general, debe ver cuidadosamente las reglas de esas API de servidor específicas sobre cómo redactar solicitudes.


Todas las respuestas son buenas, pero nadie dijo que para algunas solicitudes se requiere el tipo de contenido , debe agregar un tipo de contenido a su solicitud de esta manera:

Request request = new Request.Builder() .url(url) .addHeader("content-type", "application/json") .post(body) .build();

Si no lo agrega, recibirá un mensaje no autorizado y perderá mucho tiempo para solucionarlo.


Okhttp3 con base 64 auth

String endpoint = "https://www.example.com/m/auth/" String username = "user123"; String password = "12345"; String credentials = username + ":" + password; final String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); Request request = new Request.Builder() .url(endpoint) .header("Authorization", basic) .build(); OkHttpClient client = SomeUtilFactoryClass.buildOkhttpClient(); client.newCall(request).enqueue(new Callback() { ...