web-dev-qa-db-fra.com

Android OkHttp avec authentification de base

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:

Demande de modification POST avec authentification HTTP de base: "Impossible de réessayer le corps HTTP en streaming"

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!

54
Kerr

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

33
Jesse Wilson

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

}
66
nuss

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;
  }
})
52
David Gageot

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();
43
Alphaaa

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() {
...
6
s-hunter

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()
3
Rich Gabrielli

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.

2
Nosov Pavel

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.

1
CodeToLife

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();
0
sea cat

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();
0
Codev

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

                }
            });
0
Vayuj Rajan