具有基本身份验证的Android OkHttp

时间:2014-03-18 20:14:49

标签: android okhttp

我正在使用OkHttp库进行新项目,并且对其易用性印象深刻。我现在需要使用基本身份验证。不幸的是,缺乏工作示例代码。我正在寻找一个如何在遇到HTTP 401标头时将用户名/密码凭据传递给OkAuthenticator的示例。我看到了这个答案:

Retrofit POST request w/ Basic HTTP Authentication: "Cannot retry streamed HTTP body"

但它并没有让我走得太远。 OkHttp github repo上的样本也没有基于身份验证的示例。有没有人有一个要点或其他代码示例让我指向正确的方向?谢谢你的帮助!

11 个答案:

答案 0 :(得分:69)

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

}

答案 1 :(得分:52)

这是更新后的代码:

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

答案 2 :(得分:48)

正如@agamov所指出的那样:

  

上述解决方案有一个缺点: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();

答案 3 :(得分:33)

尝试使用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

答案 4 :(得分:6)

Okhttp3 with base 64 auth

-t

答案 5 :(得分:3)

有人要求使用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()

答案 6 :(得分:3)

在我的情况下,仅当我将授权集成到标头(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();

答案 7 :(得分:2)

所有答案都很好,但没有人说,对于某些要求 content-type ,您应该为您的请求添加内容类型,如下所示:< / p>

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

如果您不添加,则会收到未经授权消息,您将浪费大量时间进行修复。

答案 8 :(得分:1)

我注意到Android上有一些服务器API,比如django,你应该在令牌

中添加一个单词
Request request = new Request.Builder()
    .url(theUrl)
    .header("Authorization", "Token 6utt8gglitylhylhlfkghriyiuy4fv76876d68")
    .build();

,那个有问题的词是&#34;令牌&#34;。总的来说,您应该仔细查看有关如何撰写请求的特定服务器API的规则。

答案 9 :(得分:1)

在OkHttp3中,您可以通过添加OkHttpClient方法来对authenticator()本身设置授权。在您的原始呼叫返回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();

答案 10 :(得分:0)

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

                }
            });