web-dev-qa-db-ja.com

Android基本認証を使用したOkHttp

私は新しいプロジェクトにOkHttpライブラリを使用していますが、その使いやすさに感銘を受けています。今、基本認証を使用する必要があります。残念ながら、動作するサンプルコードは不足しています。 HTTP 401ヘッダーが検出されたときに、ユーザー名/パスワード認証情報をOkAuthenticatorに渡す方法の例を探しています。私はこの答えを見ました:

Retrofit POST request with Basic HTTP Authentication: "ストリーミングHTTPボディを再試行できません"

しかし、それは私をあまり遠くに行かせませんでした。 OkHttp github repo のサンプルには、認証ベースのサンプルも含まれていません。誰かが私を正しい方向に導くための要点または他のコードサンプルを持っていますか?ご協力ありがとうございます!

58
Kerr

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

更新:

名前が Authenticator に変更されました

33
Jesse Wilson

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

}
75
nuss

更新されたコードは次のとおりです。

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

@agamovが指摘したように:

前述のソリューションには1つの欠点があります。httpClientには、401応答を受信した後にのみ許可ヘッダーが追加されます。

@agamovは、各リクエストに認証ヘッダーを「手動で」追加することを提案しましたが、より良い解決策があります。 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);
    }

}

次に、すべての認証済みリクエストを作成するために使用するOkHttpクライアントにインターセプターを追加します。

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

前述のソリューションには1つの欠点があります。httpClientは、401応答を受信した後にのみ許可ヘッダーを追加します。 api-serverとの通信は次のようになります。 enter image description here

すべてのリクエストにbasic-authを使用する必要がある場合は、各リクエストに認証ヘッダーを追加するか、次のようなラッパーメソッドを使用します。

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();
}
35
agamov

Base 64認証を使用したOkhttp

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

誰かがインターセプターのKotlinバージョンを要求しました。ここに私が思いついたものがあり、それはうまく機能します:

        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

すべての回答は良好ですが、一部のリクエストではcontent-typeが必要であるため、コンテンツを追加する必要があるとは言われていません次のようにリクエストに入力します:

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

追加しない場合、nauthorizedメッセージが表示され、修正に多くの時間を費やすことになります。

2
Nosov Pavel

Android DjangoのようなトークンでWordをトークンに追加する必要があります

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

、問題のあるWordはその「トークン」です。全体として、リクエストの作成方法に関する特定のサーバーAPIのルールを注意深く確認する必要があります。

1
CodeToLife

OkHttp3では、authenticator()メソッドを追加して、OkHttpClient自体に認証を設定します。元の呼び出しが401応答で戻った後、the authenticator()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();

より安全ですが、最初にすべての401リクエストでサーバーをスパムしたくない場合は、事前認証と呼ばれるものを使用して、リクエストで最初にAuthorizationヘッダーを送信できます

String credentials = Credentials.basic("username", "password");
Request httpRequest = new Request.Builder()
                 .url("some/url")
                 .header("content-type", "application/json") 
                 .header(HttpHeaders.AUTHORIZATION, credentials)
                 .build();
1
sea cat

私の場合、ヘッダーに認証を統合した場合にのみ機能しました(OkHttpバージョン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

これはOkHttpクライアントのスニペットです。

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

今すぐリクエストしてください。基本認証は、クライアントが既に持っているので行きます。

    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