Android 带双向认证的Retrofit基础使用

  1. 参考资料

  2. 生成两个bks文件(如何生成可以参考以下链接,讲的比较详细,但是如果只是想知道如何使用,看生成部分就可以了),放入assets文件夹下:
    Android HTTPS 自制证书实现双向认证(OkHttp + Retrofit + Rxjava)

  3. 在build.gradle添加如下包:

    dependencies {
        compile 'io.reactivex:rxjava:1.2.3'
        compile 'io.reactivex:rxandroid:1.2.1'
        /**
         * Retrofit, adapter-rxjava, converter-gson must be the same version!!!
         * ↑ 就是说版本包得一致才行噻~
         */
        compile 'com.squareup.retrofit2:retrofit:2.1.0'
        compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
        compile 'com.squareup.retrofit2:converter-gson:2.1.0'
        }
    
  4. 在java/包名下,新建一个文件夹(我的叫retrofit)。
  5. 新建一个UnSafeHostnameVerifier放到retrofit下,内容如下:

    public class UnSafeHostnameVerifier implements
            HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
    
  6. 新建一个SSLHelper(这个其实所有双向认证用的都是一样的,并不是专门针对Retrofit的)放到retrofit下,内容如下:

    public class SSLHelper {
    private final static String CLIENT_PRI_KEY = "hengtiansoft.com.bks";
    private final static String TRUSTSTORE_PUB_KEY = "client-truststore.bks";
    private final static String CLIENT_BKS_PASSWORD = "hT118InsIgmA";
    private final static String TRUSTSTORE_BKS_PASSWORD = "wso2carbon";
    private final static String KEYSTORE_TYPE = "BKS";
    private final static String PROTOCOL_TYPE = "TLS";
    private final static String CERTIFICATE_STANDARD = "X509";
    
    public static SSLSocketFactory getSSLCertifcation(Context context) {
        SSLSocketFactory sslSocketFactory = null;
        try {
            // 服务器端需要验证的客户端证书,其实就是客户端的keystore
            KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
            // 客户端信任的服务器端证书
            KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE);
    
            //读取证书
            InputStream ksIn = context.getAssets().open(CLIENT_PRI_KEY);
            InputStream tsIn = context.getAssets().open(TRUSTSTORE_PUB_KEY);
    
            //加载证书
            keyStore.load(ksIn, CLIENT_BKS_PASSWORD.toCharArray());
            trustStore.load(tsIn, TRUSTSTORE_BKS_PASSWORD.toCharArray());
            ksIn.close();
            tsIn.close();
    
            //初始化SSLContext
            SSLContext sslContext = SSLContext.getInstance(PROTOCOL_TYPE);
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(CERTIFICATE_STANDARD);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_STANDARD);
            trustManagerFactory.init(trustStore);
            keyManagerFactory.init(keyStore, CLIENT_BKS_PASSWORD.toCharArray());
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
    
            sslSocketFactory = sslContext.getSocketFactory();
    
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sslSocketFactory;
    }
    
    public static OkHttpClient genericClient() {
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request()
                                .newBuilder()
                                .addHeader("Authentication-Token", "d90d790cf80d1078750e840a8922c02b-1376208214")
                                .build();
                        return chain.proceed(request);
                    }
    
                })
                .build();
        return httpClient;
     }
    }
    
  7. 根据业务逻辑,新建一个BaseResponse在retrofit文件夹下,内容如下:

    public class BaseResponse <T> {
        public static String UNKNOWN_ERROR = "未知错误";
        private boolean success;
        private String errorCode;
    
        private T data;
    
        private String msg;
    
        public BaseResponse() {
    
        }
    
        public boolean isSuccess() {
            return success;
        }
    
        public void setSuccess(boolean success) {
            this.success = success;
        }
    
        public String getErrorCode() {
            return errorCode;
        }
    
        public void setErrorCode(String errorCode) {
            this.errorCode = errorCode;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
         }
        }
    
  8. 根据业务逻辑,新建一个数据传输类(按照接口来写,在此选取一个Token类),内容如下:

    public class Token {
        private String TGT;
        private String token;
    
        public String getTGT() {
            return TGT;
        }
    
        public void setTGT(String TGT) {
            this.TGT = TGT;
        }
    
        public String getToken() {
            return token;
        }
    
        public void setToken(String token) {
            this.token = token;
        }
       }
    
  9. 根据业务返回,新建一个CallBack,内容如下:

    public abstract class RetrofitCallBack<T extends BaseResponse> implements Callback<T> {
        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            if (response.raw().code() == 200) {//200是服务器有合理响应
                if (response.body() != null) {
                    onBizSuccess(response.body());
                } else {
    
                    onBizFail(originResult, response.body(), response.raw().code());
    
                }
            } else {//失败响应
                onFailure(call, new RuntimeException("response error,detail = " + response.raw().toString()));
            }
        }
    
        @Override
        public void onFailure(Call<T> call, Throwable ex) {//网络问题会走该回调
            if (ex instanceof SocketTimeoutException) {
                //
            } else if (ex instanceof ConnectException) {
                //
            } else if (ex instanceof RuntimeException) {
                //
            }
            onFail(ex);
        }
    
        public abstract void onBizSuccess(T result);
    
        public abstract void onBizFail(String originResult, T result, int returnCode);
        public abstract void onFail(Throwable ex);  
    }
    
  10. 根据业务模块区分,新建一个service(我在这里选取一个AuthService),内容如下:

    public interface AuthService {
    /**
     * 获取token
     *
     * @param appKey
     * @param token       
     * @param requestBody
     * @return
     */
    @POST("/services/htmf-auth/getToken")
    Call<BaseResponse<Token>> getToken(@Header("AppKey") String appKey, @Body RequestBody requestBody);
    
    }
    
  11. 新建一个RetrofitClient类放在retrofit下,内容如下:

    public class RetrofitClient {
    
        public static final String HTTP_CACHE_DIR = "DemoCache";
    
    //ip地址
       public static final String BASE_URL = "https://xxx.xxx.com";
    
        /**
         * 网络请求接口包装类,可细分多个Service
         **/
        public AuthService authService;
        public static final long DEFAULT_TIMEOUT = 7676l;
        private static Context mContext;
    
        /**
         * 在访问HttpMethods时创建延迟加载的单例
         **/
        private static class SingletonHolder {
            private static final RetrofitClient INSTANCE = new RetrofitClient(mContext);
        }
    
        // 获取单例
        public static RetrofitClient getInstance(Context context) {
            if (context != null) {
                mContext = context;
            }
            return SingletonHolder.INSTANCE;
        }
    
    
        private RetrofitClient(Context context) {
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
    
            builder.sslSocketFactory(SSLHelper.getSSLCertifcation(context));
            builder.hostnameVerifier(new UnSafeHostnameVerifier());
            // 网络请求的缓存机制,无网络也能显示数据
            File cacheFile = new File(context.getCacheDir(), HTTP_CACHE_DIR);
            Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
            builder.addNetworkInterceptor(new HttpCacheInterceptor());
    
            // 保持请求是同一个cookie
            CookieManager cookieManager = new CookieManager();
            cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
    
            // 其他设置
            builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
                    .readTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
                    .retryOnConnectionFailure(true)// 错误重连
    //                .addInterceptor(addQueryParameterInterceptor)// 公共参数
                    .cache(cache);// 缓存目录
    //                .cookieJar(new JavaNetCookieJar(cookieManager));
    
            OkHttpClient okHttpClient = builder.build();
    
            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").serializeNulls().create();
    
            Retrofit retrofit = new Retrofit.Builder()
                    .client(okHttpClient)// okhttp的实现
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())// RxJava支持
                    .addConverterFactory(GsonConverterFactory.create(gson))// Gson支持
                    .baseUrl(BASE_URL)// 请求地址
                    .build();
            // 可使用ServiceFactory细分接口服务
            authService = retrofit.create(AuthService.class);
            eventAnalyticService = retrofit.create(EventAnalyticService.class);
        }
    
    
        class HttpCacheInterceptor implements Interceptor {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                if (!NetWorkUtil.isNetConnected(mContext)) {
                    request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
                }
                Response originalResponse = chain.proceed(request);
                if (NetWorkUtil.isNetConnected(mContext)) {
                    // 有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
                    String cacheControl = request.cacheControl().toString();
                    // int maxAge = 0;
                    return originalResponse.newBuilder()
                            .header("Cache-Control", cacheControl)//"public, max-age="+maxAge
                            .removeHeader("Pragma")// 清除头信息,因为服务器如果不支持会返回一些干扰信息,不清除下面无法生效
    
                            .build();
                } else {
                    int maxStale = 60 * 60 * 24 * 28;// 2419200
                    return originalResponse.newBuilder()
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .removeHeader("Pragma")
                            .build();
                }
        }
    }
    
  12. 已经可以调用啦~

    Map<String, String>  values="";//此处的value值自己添加
    String postTokenStr = JSON.toJSONString(values);
    RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), postTokenStr);        
    RetrofitClient.getInstance(context).authService.getToken("", "", body).enqueue(new RetrofitCallBack<BaseResponse<Token>>() {
    
    
                @Override
                public void onBizSuccess(BaseResponse<Token> result) {
    
                }
    
                @Override
                public void onBizFail(String originResult, BaseResponse<Token> result, int returnCode) {
    
                }
    
                @Override
                    public void onFail(Throwable ex) {
                }
    
            });
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值