具有基本身份验证的Android OkHttp

Ker*_*err 63 android okhttp

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

使用基本HTTP身份验证更改POST请求:"无法重试流式HTTP正文"

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

小智 75

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

}
Run Code Online (Sandbox Code Playgroud)

  • 这需要到顶部:) (7认同)
  • @nuss +1为'永不放弃'评论XD (5认同)
  • 您如何将其插入方法中?我不断收到编译器错误:“无法应用OKHttpClient中的身份验证器(匿名okhttp3.Authenticator)” (2认同)

Dav*_*eot 53

这是更新的代码:

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;
  }
})
Run Code Online (Sandbox Code Playgroud)

  • 这是使用OkHttp 2.x的当前答案 (2认同)

Alp*_*aaa 49

正如@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);
    }

}
Run Code Online (Sandbox Code Playgroud)

然后,只需将拦截器添加到您将用于进行所有经过身份验证的请求的OkHttp客户端:

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new BasicAuthInterceptor(username, password))
    .build();
Run Code Online (Sandbox Code Playgroud)

  • 这非常有效.正是我需要避免多次401调用.我的API要求对所有呼叫进行身份验证. (2认同)

aga*_*mov 36

上述解决方案有一个缺点:httpClient仅在收到401响应后才添加授权头.以下是我与api-server的通信方式: 在此输入图像描述

如果您需要为每个请求使用basic-auth,最好将auth-header添加到每个请求或使用这样的包装器方法:

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();
}
Run Code Online (Sandbox Code Playgroud)


Jes*_*son 34

尝试使用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;
  }
});
Run Code Online (Sandbox Code Playgroud)

更新:

重命名为Authenticator

  • 在OkHttp 2.0中重命名为[Authenticator](http://square.github.io/okhttp/javadoc/com/squareup/okhttp/Authenticator.html). (12认同)
  • [Authenticator]的新链接(https://square.github.io/okhttp/2.x/okhttp/com/squareup/okhttp/Authenticator.html) (4认同)

s-h*_*ter 6

Okhttp3与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() {
...
Run Code Online (Sandbox Code Playgroud)

  • `okhttp3.Credentials.basic(user,pass)`这样做,所以我认为它应该是首选的(因为它导致更少的代码来保持). (4认同)
  • @Shorn`okhttp3.Credentials.basic(user,pass)`不会发出任何请求或更改任何行为,它只是将用户名和密码转换为基本的auth字符串. (3认同)

小智 6

有人要求提供 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()
Run Code Online (Sandbox Code Playgroud)


sea*_*cat 5

OkHttpClient在OkHttp3中,您可以通过添加方法来设置自身的授权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();
Run Code Online (Sandbox Code Playgroud)

虽然它更安全,但如果您不想首先向服务器发送所有 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();
Run Code Online (Sandbox Code Playgroud)


Cod*_*dev 5

就我而言,它仅在我将授权集成到标头中时才有效(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();
Run Code Online (Sandbox Code Playgroud)