Kerr
Estoy usando la biblioteca OkHttp para un nuevo proyecto y estoy impresionado con su facilidad de uso. Ahora necesito usar la autenticación básica. Desafortunadamente, hay una escasez de código de muestra que funcione. Estoy buscando un ejemplo de cómo pasar las credenciales de nombre de usuario/contraseña a OkAuthenticator cuando se encuentra un encabezado HTTP 401. Vi esta respuesta:
Actualización de solicitud POST con autenticación HTTP básica: “No se puede volver a intentar el cuerpo HTTP transmitido”
pero no me llevó demasiado lejos. Las muestras en el OkHttp repositorio de github tampoco presentó una muestra basada en autenticación. ¿Alguien tiene una esencia u otra muestra de código para orientarme en la dirección correcta? ¡Gracias por tu ayuda!
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;
}
}
-
Esto tiene que ir a la cima 🙂
– Ionut
17 de febrero de 2016 a las 17:12
-
¡Gracias por el seguimiento!
– Kerr
25 de febrero de 2016 a las 21:26
-
¿Cómo conectas esto dentro de un método? Sigo recibiendo un error del compilador: “no se puede aplicar el autenticador en OKHttpClient (okhttp3.Authenticator anónimo)”
– Mike6679
1 dic 2016 a las 20:00
-
ahhh ya veo, Authenticator es una interfaz.
– Mike6679
1 de diciembre de 2016 a las 20:46
-
@nuss +1 para el
never give up
comenta XD– Banana
9 dic 2018 a las 10:15
Como 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();
-
Esto funciona perfectamente. Exactamente lo que necesitaba para evitar múltiples llamadas al 401. Mi API requiere que todas las llamadas sean autenticadas.
– Hackmodford
10 de agosto de 2016 a las 19:44
-
¿Hay una versión kotlin de este Interceptor? @Alphaaaa
– stebak
21 de marzo de 2018 a las 8:46
-
@KBJ Este interceptor funciona con OkHttp, que es una biblioteca de Java. Las bibliotecas HTTP generalmente permiten trabajar con interceptores, por lo que si encuentra uno para Kotlin, puede implementar algo similar a esto 🙂
– alfaaaa
21 de marzo de 2018 a las 18:28
-
En mi opinión, podemos usar la interfaz Interceptor si todos los puntos finales requieren autenticación o si tenemos una lista finita de puntos finales con este requisito. Cuando no sabemos exactamente qué puntos finales requieren autenticación, podemos usar la interfaz del Autenticador. Cuando lo necesitemos, podemos mezclar estos 2 enfoques para evitar solicitudes dobles (401 -> 200) y evitar agregar un encabezado de Autorización en lugares donde no lo necesitamos (problema de seguridad).
– ultraón
17 dic 2018 a las 23:32
-
Esta no es la manera más eficiente de hacer esto. La razón es que el código interceptor se ejecutará cada vez que hagamos una solicitud al servidor. Entonces, de esta manera estaremos creando un
request.newBuilder()
cada vez Mientras que, el autenticador debe agregarse solo a los del cliente.– Shriharsh Pathak
14 de diciembre de 2021 a las 8:17
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;
}
})
-
Esta es la respuesta actual usando OkHttp 2.x
– Ian Timmis
03/12/2016 a las 20:39
Jesse Wilson
Intenta usar OkAutenticador:
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 Autenticador
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 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();
}
-
Buena atrapada. Escribí una respuesta mejorada que se basa en la tuya: stackoverflow.com/a/36056355/2091700
– alfaaaa
17 de marzo de 2016 a las 9:27
guardagujas
Okhttp3 con autenticación base 64
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() {
...
-
Buena atrapada. Escribí una respuesta mejorada que se basa en la tuya: stackoverflow.com/a/36056355/2091700
– alfaaaa
17 de marzo de 2016 a las 9:27
rico gabrielli
Alguien pidió una versión de Kotlin del interceptor. Esto es lo que se me ocurrió y funciona muy bien:
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()
-
Es bueno ver que siguen llegando nuevas respuestas a mi pregunta a medida que evolucionan los lenguajes y las técnicas.
– Kerr
27 de abril de 2018 a las 12:57
-
¡Interceptor es la herramienta equivocada para hacer eso! Utilice el Autenticador en su lugar. Te evitarás muchos problemas.
– Dawid Hyży
13 de marzo de 2019 a las 9:30
Pide que esto se implemente github.com/square/okhttp/issues/2143
– pomo
19 de septiembre de 2016 a las 7:53