【问题标题】:Retrofit and OkHttp basic authentication改造和 OkHttp 基本认证
【发布时间】:2017-04-12 09:51:58
【问题描述】:

我正在尝试将基本身份验证(用户名和密码)添加到 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,this tutorial 建议使用 AuthenticationInterceptor,但是这个类不可用。 添加凭据的正确位置在哪里?我是否必须将它们添加到我的拦截器、客户端或改造对象中?我该怎么做?

【问题讨论】:

    标签: android retrofit2 okhttp


    【解决方案1】:

    寻找解决方案

    1.编写一个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);
        }
    
    }
    

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

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

    【讨论】:

    【解决方案2】:

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

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

    用法

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

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

    More information see here.

    【讨论】:

    • 用户模型中有哪些字段?
    • 我正在使用 Retrofit 2,但在 httpClient.addInterceptor(interceptor);它说:必需的类型:提供的拦截器:AuthenticationInterceptor
    【解决方案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();
    

    【讨论】:

      猜你喜欢
      • 2016-02-26
      • 2016-01-25
      • 2014-07-12
      • 2011-05-03
      • 2014-05-02
      • 2015-12-28
      • 2014-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多