J'utilise la bibliothèque OkHttp pour un nouveau projet et je suis impressionné par sa facilité d'utilisation. J'ai maintenant besoin d'utiliser l'authentification de base. Malheureusement, il y a une pénurie d'échantillons de code de travail. Je cherche un exemple montrant comment transmettre des informations d'identification de nom d'utilisateur/mot de passe à OkAuthenticator lorsqu'un en-tête HTTP 401 est rencontré. J'ai visionné cette réponse:
mais cela ne m'a pas conduit trop loin. Les échantillons sur le OkHttp github repo ne comportaient pas non plus d’échantillon basé sur l’authentification. Quelqu'un a-t-il un exemple de code Gist ou autre pour me faire pointer dans la bonne direction? Merci pour votre aide!
Essayez d’utiliser 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;
}
});
METTRE À JOUR:
Renommé en Authenticator
Code de mise à jour pour 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;
}
}
Voici le code mis à jour:
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;
}
})
Comme l'a souligné @agamov:
La solution susmentionnée présente un inconvénient: httpClient ajoute En-têtes d'autorisation seulement après avoir reçu la réponse 401
@agamov a ensuite proposé d'ajouter "manuellement" des en-têtes d'authentification à chaque demande, mais il existe une meilleure solution: utilisez une 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);
}
}
Ensuite, ajoutez simplement l'intercepteur à un client OkHttp que vous utiliserez pour effectuer toutes vos demandes authentifiées:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor(username, password))
.build();
Okhttp3 avec 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() {
...
Quelqu'un a demandé une version Kotlin de l'intercepteur. Voici ce que je suis venu avec et cela fonctionne très 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()
Toutes les réponses sont bonnes mais personne ne dit que pour certaines requêtes content-type _ est requis, vous devez ajouter un type de contenu à votre requête comme ceci:
Request request = new Request.Builder()
.url(url)
.addHeader("content-type", "application/json")
.post(body)
.build();
Si vous ne l'ajoutez pas, vous obtiendrez le message Non autorisé et vous perdrez beaucoup de temps à le corriger.
J'ai remarqué sur Android avec certaines API de serveur comme Django, vous devriez ajouter un mot dans le token
Request request = new Request.Builder()
.url(theUrl)
.header("Authorization", "Token 6utt8gglitylhylhlfkghriyiuy4fv76876d68")
.build();
, où ce mot problématique est ce "jeton". Globalement, vous devez lire attentivement les règles de ces API de serveur spécifiques sur la manière de composer des demandes.
Dans OkHttp3, vous définissez l'autorisation sur la OkHttpClient
elle-même en ajoutant la méthode authenticator()
. Une fois que vos appels d'origine sont revenus avec la réponse 401, the authenticator()
ajoute l'en-tête Authorization
.
new OkHttpClient.Builder()
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.readTimeout(10000, TimeUnit.MILLISECONDS)
.authenticator(new Authenticator() {
@Nullable
@Override
public Request authenticate(@NonNull Route route, @NonNull Response response) {
if (response.request().header(HttpHeaders.AUTHORIZATION) != null)
return null; //if you've tried to authorize and failed, give up
String credential = Credentials.basic("username", "pass");
return response.request().newBuilder().header(HttpHeaders.AUTHORIZATION, credential).build();
}
})
.build();
Bien que ce soit plus sécurisé, si vous ne souhaitez pas envoyer de spam au serveur avec toutes les 401 demandes, vous pouvez utiliser un processus appelé pré-authentification, dans lequel vous envoyez l'en-tête Authorization
pour commencer avec vos demandes
String credentials = Credentials.basic("username", "password");
Request httpRequest = new Request.Builder()
.url("some/url")
.header("content-type", "application/json")
.header(HttpHeaders.AUTHORIZATION, credentials)
.build();
Dans mon cas, cela ne fonctionnait que lorsque j'ai intégré l'autorisation dans l'en-tête (OkHttp Version 4.0.1):
Request request = new Request.Builder()
.url("www.url.com/api")
.addHeader("Authorization", Credentials.basic("username", "password"))
.build();
Request response = client.newCall(request).execute();
Ceci est un extrait de code pour OkHttp Client:
OkHttpClient client = new OkHttpClient.Builder()
.authenticator(new Authenticator() {
@Override public Request authenticate(Route route, Response
response) throws IOException {
if (response.request().header("Authorization") != null) {
return null; // Give up, we've already attempted to
authenticate.
}
System.out.println("Authenticating for response: " + response);
System.out.println("Challenges: " + response.challenges());
String credential = Credentials.basic(username, password);
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
}) .build();
Faites une demande maintenant. L'authentification de base ira comme le client l'a déjà.
Request request = new Request.Builder().url(JIRAURI+"/issue/"+key).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("onFailure: "+e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println( "onResponse: "+response.body().string());
}
});