wake-up-neo.com

Android OkHttp mit Standardauthentifizierung

Ich verwende die OkHttp-Bibliothek für ein neues Projekt und bin beeindruckt von der Benutzerfreundlichkeit. Ich muss jetzt die Standardauthentifizierung verwenden. Leider gibt es einen Mangel an funktionierendem Beispielcode. Ich suche ein Beispiel, wie Benutzername/Kennwort-Anmeldeinformationen an den OkAuthenticator übergeben werden, wenn ein HTTP 401-Header gefunden wird. Ich habe diese Antwort gesehen:

Retrofit POST - Anforderung mit grundlegender HTTP-Authentifizierung: "Gestreamter HTTP-Body kann nicht wiederholt werden"

aber es hat mich nicht zu weit gebracht. Die Beispiele im OkHttp github repo enthielten auch kein authentifizierungsbasiertes Beispiel. Hat jemand eine Gist oder ein anderes Codebeispiel, um mich in die richtige Richtung zu weisen? Danke für deine Hilfe!

54
Kerr

Versuchen Sie es mit 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;
  }
});

AKTUALISIEREN:

Umbenannt in Authenticator

33
Jesse Wilson

Aktualisierungscode für 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

Hier ist der aktualisierte Code:

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

Wie @agamov darauf hinweist:

Die oben genannte Lösung hat einen Nachteil: httpClient fügt .__ hinzu. Berechtigungsheader erst nach Erhalt der Antwort 401

@agamov schlug dann vor, jeder Anfrage "manuell" Authentifizierungsheader hinzuzufügen. Es gibt jedoch eine bessere Lösung: Verwenden Sie eine 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);
    }

}

Fügen Sie dann einfach den Interceptor einem OkHttp-Client hinzu, den Sie für alle Ihre authentifizierten Anforderungen verwenden werden:

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

Die oben erwähnte Lösung hat einen Nachteil: httpClient fügt Autorisierungsheader erst nach Erhalt der Antwort 401 hinzu. So sah meine Kommunikation mit dem API-Server aus: enter image description here

Wenn Sie basic-auth für jede Anfrage verwenden müssen, fügen Sie Ihre Auth-Header besser zu jeder Anfrage hinzu oder verwenden Sie eine Wrapper-Methode wie diese:

private Request addBasicAuthHeaders(Request request) {
    final String login = "your_login";
    final String password = "[email protected]$w0rd";
    String credential = Credentials.basic(login, password);
    return request.newBuilder().header("Authorization", credential).build();
}
35
agamov

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

Jemand fragte nach einer Kotlin-Version des Interceptors. Hier ist was ich mir ausgedacht habe und es funktioniert super:

        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

Alle Antworten sind gut, aber niemand hat gesagt, dass für einige Anfragencontent-typeerforderlich ist, Sie sollten Ihrer Anfrage einen Content-Typ wie folgt hinzufügen:

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

Wenn Sie es nicht hinzufügen, erhalten Sie Unauthorized message und verschwenden viel Zeit, um es zu beheben.

2
Nosov Pavel

Ich habe bei Android mit einigen Server-APIs wie Django festgestellt, dass Sie ein Wort im Token hinzufügen sollten

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

, wo das problematische Wort das "Token" ist. Im Allgemeinen sollten Sie die Regeln dieser speziellen Server-APIs zum Erstellen von Anforderungen sorgfältig prüfen.

1
CodeToLife

In OkHttp3 legen Sie die Berechtigung für die OkHttpClient selbst fest, indem Sie die authenticator()-Methode hinzufügen. Nachdem Ihre ursprünglichen Anrufe mit der Antwort 401 zurückgekommen sind, fügt the authenticator() den Header Authorization hinzu

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

Obwohl es sicherer ist, wenn Sie den Server nicht mit allen 401 Anfragen anstoßen möchten, können Sie eine so genannte Vorauthentifizierung verwenden, bei der Sie den Authorization-Header mit Ihren Anforderungen senden

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

In meinem Fall hat es nur funktioniert, wenn ich die Autorisierung in den Header integriert habe (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

Dies ist ein Ausschnitt für 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(); 

Fordern Sie jetzt eine Anfrage an. Basic auth wird gehen, da der Client dies bereits hat.

    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