带有基本身份验证的 Android OkHttp

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22490057/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:03:50  来源:igfitidea点击:

Android OkHttp with Basic Authentication

androidokhttp

提问by Kerr

I'm using the OkHttp library for a new project and am impressed with its ease of use. I now have a need to use Basic Authentication. Unfortunately, there is a dearth of working sample code. I'm seeking an example of how to pass username / password credentials to the OkAuthenticator when an HTTP 401 header is encountered. I viewed this answer:

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

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

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

but it didn't get me too far. The samples on the OkHttp github repodidn't feature an authentication-based sample either. Does anyone have a gist or other code sample to get me pointed in the right direction? Thanks for your assistance!

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

采纳答案by Jesse Wilson

Try using OkAuthenticator:

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

UPDATE:

更新:

Renamed to Authenticator

重命名为Authenticator

回答by nuss

Update Code for okhttp3:

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

}

回答by David Gageot

Here's the updated 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;
  }
})

回答by Alphaaa

As pointed out by @agamov:

正如@agamov 所指出的:

The aforementioned solution has one drawback: httpClient adds authorization headers only after receiving 401 response

上述解决方案有一个缺点:httpClient 只有在收到 401 响应后才添加授权头

@agamov proposed then to "manually" add authentication headers to each request, but there is a better solution: use an Interceptor:

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

}

Then, simply add the interceptor to an OkHttp client that you will be using to make all your authenticated requests:

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

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

回答by agamov

The aforementioned solution has one drawback: httpClient adds authorization headers only after receiving 401 response. Here's how my communication with api-server looked like: enter image description here

上述解决方案有一个缺点:httpClient 只有在收到 401 响应后才添加授权头。这是我与 api-server 的通信方式: 在此处输入图片说明

If you need to use basic-auth for every request, better add your auth-headers to each request or use a wrapper method like this:

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

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

回答by s-hunter

Okhttp3 with base 64 auth

Okhttp3 使用 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() {
...

回答by Rich Gabrielli

Someone asked for a Kotlin version of the interceptor. Here is what I came up with and it works great:

有人要求提供 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()

回答by CodeToLife

I noticed on Android with some server APIs like django you should add a word in token

我注意到在 Android 上有一些像 django 这样的服务器 API,你应该在令牌中添加一个词

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

, where that problematic word is that "Token ". Overall you should carefully see rules of those specific server APIs about how to compose requests.

,那个有问题的词是“令牌”。总体而言,您应该仔细查看这些特定服务器 API 的有关如何编写请求的规则。

回答by Codev

In my case it only worked when I integrated authorization into the header (OkHttp Version 4.0.1):

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

回答by sea cat

In OkHttp3, you set the authorization on the OkHttpClientitself by adding the authenticator()method. After your original calls come back with the 401 response, the authenticator()adds the Authorizationheader

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

Although it's more secure, if you don't want to spam the server with all the 401 requests in the first place, you can use something called preauthentication, where you send the Authorizationheader to begin with on your requests

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