Retrofit和OkHttp基本认证

52

我正在尝试为Retrofit OkHttp客户端添加基本身份验证(用户名和密码)。这是我目前的代码:

private static Retrofit createMMSATService(String baseUrl, String user, String pass) {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    return retrofit;
}

我正在使用Retrofit 2.2,这个教程建议使用AuthenticationInterceptor,但是这个类不存在。 在哪里添加凭据?我需要把它们添加到我的拦截器、客户端还是Retrofit对象中?我该怎么做?

4个回答

114

寻找解决方案

1.编写一个拦截器类

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

}

2. 最后,将拦截器添加到OkHttp客户端中。

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

你有这个拦截器的Kotlin版本可用吗?我一直在使用的Kotlin版本出现了错误。@Rajasekhar - stebak
3
@KBJ 我是这样实现的:https://gist.github.com/seccomiro/85446c4849855615d1938133bce30738 - Diego Stiehl
3
是用 addInterceptor 还是 addNetworkInterceptor - IgorGanapolsky

9

Retrofit 2

    public class ServiceGenerator {

    public static final String API_BASE_URL = "https://your.api-base.url";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    private static Retrofit retrofit = builder.build();

    public static <S> S createService(Class<S> serviceClass) {
        return createService(serviceClass, null, null);
    }

    public static <S> S createService(
            Class<S> serviceClass, String username, String password) {
        if (!TextUtils.isEmpty(username)
                && !TextUtils.isEmpty(password)) {
            String authToken = Credentials.basic(username, password);
            return createService(serviceClass, authToken);
        }

        return createService(serviceClass, null);
    }

    public static <S> S createService(
            Class<S> serviceClass, final String authToken) {
        if (!TextUtils.isEmpty(authToken)) {
            AuthenticationInterceptor interceptor =
                    new AuthenticationInterceptor(authToken);

            if (!httpClient.interceptors().contains(interceptor)) {
                httpClient.addInterceptor(interceptor);

                builder.client(httpClient.build());
                retrofit = builder.build();
            }
        }

        return retrofit.create(serviceClass);
    }
}

Retrofit 1.9

public class ServiceGenerator {

    public static final String API_BASE_URL = "https://your.api-base.url";

    private static RestAdapter.Builder builder = new RestAdapter.Builder()
                .setEndpoint(API_BASE_URL)
                .setClient(new OkClient(new OkHttpClient()));

    public static <S> S createService(Class<S> serviceClass) {
        return createService(serviceClass, null, null);
    }

    public static <S> S createService(Class<S> serviceClass, String username, String password) {
        if (username != null && password != null) {
            // concatenate username and password with colon for authentication
            String credentials = username + ":" + password;
            // create Base64 encodet string
            final String basic =
                    "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

            builder.setRequestInterceptor(new RequestInterceptor() {
                @Override
                public void intercept(RequestFacade request) {
                    request.addHeader("Authorization", basic);
                    request.addHeader("Accept", "application/json");
                }
            });
        }

        RestAdapter adapter = builder.build();
        return adapter.create(serviceClass);
    }
}

AuthenticationInterceptor.java

    public class AuthenticationInterceptor implements Interceptor {

    private String authToken;

    public AuthenticationInterceptor(String token) {
        this.authToken = token;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();

        Request.Builder builder = original.newBuilder()
                .header("Authorization", authToken);

        Request request = builder.build();
        return chain.proceed(request);
    }
}

使用方法

Retrofit 2

接口

public interface LoginService {  
    @POST("/login")
    Call<User> basicLogin();
}

请求方

LoginService loginService =  
   ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
Call<User> call = loginService.basicLogin();  
call.enqueue(new Callback<User >() {  
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        if (response.isSuccessful()) {
            // user object available
        } else {
            // error response, no access to resource?
        }
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
        // something went completely south (like no internet connection)
        Log.d("Error", t.getMessage());
    }
}

Retrofit 1.9

接口

public interface LoginService {  
    @POST("/login")
    void basicLogin(Callback<User> cb);
}

请求者

LoginService loginService =  
    ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
loginService.basicLogin(new Callback<User>() {  
    @Override
    public void success(User user, Response response) {
        // user object available
    }

    @Override
    public void failure(RetrofitError error) {
        // handle errors, too
    }
});

点击此处查看更多信息。


用户模型中有哪些字段? - Shrikant
我正在使用Retrofit 2,但在httpClient.addInterceptor(interceptor)处遇到了类型转换错误。它说: 所需类型:Interceptor 提供的类型:AuthenticationInterceptor - Faizan Haidar Khan

3
当然,使用身份验证拦截器是正确的方式(如其他答案所述)。不过,如果您只需要基本身份验证来进行单个调用,则可以直接在 Retrofit 请求中添加身份验证头:
import okhttp3.Credentials

// Create credentials
val login = "some login"
val password = "some password"
// Below code will create correct Base64 encoded Basic Auth credentials
val credentials = Credentials.basic(login, password)

// Then in your Retrofit API interface
interface MyApi {
    @POST("get_user")
    fun getUser(@Header("Authorization") credentials: String): ResponseBody
}

3

添加头部拦截器

public class HeaderInterceptor implements Interceptor {

    private PreferencesRepository mPrefs;
    private String mAuth;

    public HeaderInterceptor(PreferencesRepository p) {
        mPrefs = p;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        mAuth = (mPrefs.getAuthToken() != null)?mPrefs.getAuthToken():"";
        Request r = chain.request()
                .newBuilder()
                .addHeader("Accept", "application/json")
                // authorization token here
                .addHeader("Authorization", "Bearer" + mAuth)
                .build();

        return chain.proceed(r);
    }
}

添加缓存拦截器(可选)

public class CacheInterceptor implements Interceptor {

    Context mContext;

    public CacheInterceptor(Context context) {
        this.mContext = context;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();

        if (request.method().equals("GET")) {
            if (DeviceUtils.isConnected(mContext)) {
                request = request.newBuilder()
                        .header(Constant.CACHE_CONTROL, "only-if-cached")
                        .build();
            } else {
                request = request.newBuilder()
                        .header(Constant.CACHE_CONTROL, "public, max-stale=2419200")
                        .build();
            }
        }

        Response originalResponse = chain.proceed(request);
        return originalResponse.newBuilder()
                .header(Constant.CACHE_CONTROL, "max-age=600")
                .build();
    }
}

实施它。
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
logger.setLevel(HttpLoggingInterceptor.Level.BODY);

long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(new File(mContext.getCacheDir(), "http"), SIZE_OF_CACHE);

new OkHttpClient.Builder()
                    .addInterceptor(logger)
                    .addInterceptor(new HeaderInterceptor(u))
                    .cache(cache)
                    .addNetworkInterceptor(new CacheInterceptor(mContext))
                    .connectTimeout(Constant.CONNECTTIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(Constant.READTIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(Constant.WRITETIMEOUT, TimeUnit.SECONDS)
                    .build();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接