android Retrofit+OkHttp使用自制的证书实现https安全传输

相信大伙在项目中多少都遇到网络安全传输的问题,比方说涉及金额方面的订单、机密安全数据、再比方说使用友盟分享或三方登录中的appsecret(官方建议从后台获取),这些问题困扰我们不得不使用https,但是互联网企业最看重的就是效率,公司可能会因为人力或者资金方面的原因申请CA可能需要有困难(审核时间太久了),所以告诉大家在android开发中,如何使用自制的证书来实现密文传输。

至于如何生成自制证书在这里我就不叙述了(你直接交给后台的人去弄吧大笑,本身就是他的活),他生成好后会给你两个文件 CA.p12、XXX.p12(xxx是客户端的私钥) 还有解开这两个加密文件的密码KEY_STORE_TRUST_PASSWORD(CA的密码)、KEY_STORE_PASSWORD(客户端的私钥密码)。(注:p12是秘钥加密后的一种格式,当然也可以是别的格式,不过代码会有些许调整)

使用Retrofit+OkHttp无外乎就几个动作

1.实例化Retrofit  initRetrofitClient(host);

2.实例化Okhttp initOkHttpClient();  然后将其配置到Retrofit 中   builder.client(okHttpClient)

3.创建接口对象  retrofit.create(cls);

以上是常规的http格式,要实现https只需要在其中配置几行语句就能实现

首先把生成的CA.p12、XXX.p12导入到android studio的raw目录中(如果没有文件夹,右键创建)




然后对okHttp进行如下配置

 private static void initRetrofitClient(String host) {
        initOkHttpClient();
        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
                .create();
        retrofit = new Retrofit.Builder()
                .baseUrl(host)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(okHttpClient)
                .build();
    }

    private static void initOkHttpClient() {
        if (okHttpClient == null) {
            // 因为BaseUrl不同所以这里Retrofit不为静态,但是OkHttpClient配置是一样的,静态创建一次即可
            cacheFile = new File(BaseApp.getContext().getCacheDir(),
                    "HttpCache"); // 指定缓存路径
            Cache cache = new Cache(cacheFile, 1024 * 1024 * 200); // 指定缓存大小200Mb
            // 云端响应头拦截器,用来配置缓存策略
            okHttpBuilder = new OkHttpClient.Builder();
            okHttpBuilder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            okHttpClient = okHttpBuilder
                    .readTimeout(15, TimeUnit.SECONDS)
                    .connectTimeout(15, TimeUnit.SECONDS)
                    .retryOnConnectionFailure(true)
                    .addNetworkInterceptor(new StethoInterceptor())//chrome工具调试的中间件
                    .addInterceptor(new HttpCacheInterceptor())
                    .addInterceptor(new LoggingInterceptor())
                    .cache(cache)
                    .sslSocketFactory(getSocketFactory(BaseApp.getContext()))
                    .build();

        }
    }
在这里有用的代码就是在初始化okhttpBuilder后设置
okHttpBuilder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
必须放在okhttp实例化之前

然后接下来就是在okhttp中配置

.sslSocketFactory(getSocketFactory(BaseApp.getContext()))
下面是获取SSLSocketFactory实例的关键代码

private static final String KEY_STORE_TYPE_BKS = "bks";//证书类型
    private static final String KEY_STORE_TYPE_P12 = "PKCS12";//证书类型


    private static final String KEY_STORE_PASSWORD = "CLIENT_PASSWORD";//(客户端证书密码)
    private static final String KEY_STORE_TRUST_PASSWORD = "CA_PASSWRORD";//授信证书密码(CA机构证书密码)

    public static SSLSocketFactory getSocketFactory(Context context) {
        InputStream trust_input = context.getResources().openRawResource(R.raw.ca);//CA机构授信证书
        InputStream client_input = context.getResources().openRawResource(R.raw.tvfan);//客户端证书
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
            trustStore.load(trust_input, KEY_STORE_TRUST_PASSWORD.toCharArray());
            KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
            keyStore.load(client_input, KEY_STORE_PASSWORD.toCharArray());
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray());
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
            SSLSocketFactory factory = sslContext.getSocketFactory();
            return factory;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                trust_input.close();
                client_input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


这样就能简单的实现https协议 微笑,但是这种自制的证书并不能实现绝对的安全传输(不然CA机构岂不喝西北风了)!

亲测成功 Good Luck!

如果你还是没有搞定
1,请先判断后台的https协议有没有搭建好 这里给大家一个代码测试服务器是否搭建正确(不然搞了半天,发现不是自己的问题那可就苦逼了)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

public class HTTPSTest {

	private static final String CLIENT_KEY_STORE = "E:/DOC/HTTPS/MyFiles/userCenter/tvfan.p12";
	private static final String CLIENT_TRUST_STORE = "E:/DOC/HTTPS/MyFiles/userCenter/ca.p12";

	private static final String CLIENT_KEY_STORE_PASSWORD = "CLIENT_PASSWORD"; //客户端的密码
	private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "CA_PASSWORD";//ca的密码

	public static void main(String args[]) throws Exception {
		certTest1();
	}
	
	public static void certTest1() throws Exception {
		String httpsURL = "https://192.168.17.88/userCenter/"; //记得把路径换了
		System.setProperty("javax.net.ssl.keyStore", CLIENT_KEY_STORE);
		System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
		System.setProperty("javax.net.ssl.keyStorePassword", CLIENT_KEY_STORE_PASSWORD);
		System.setProperty("javax.net.ssl.trustStore", CLIENT_TRUST_STORE);
		System.setProperty("javax.net.ssl.trustStoreType", "pkcs12");
		System.setProperty("javax.net.ssl.trustStorePassword", CLIENT_TRUST_KEY_STORE_PASSWORD);

		URL myurl = new URL(httpsURL);
		HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
		con.setHostnameVerifier(hv);
		InputStream ins = con.getInputStream();
		InputStreamReader isr = new InputStreamReader(ins);
		BufferedReader in = new BufferedReader(isr);
		String inputLine = null;
		while ((inputLine = in.readLine()) != null) {
			System.out.println(inputLine);
		}
		in.close();
	}

	private static HostnameVerifier hv = new HostnameVerifier() {
		public boolean verify(String urlHostName, SSLSession session) {
			return urlHostName.equals(session.getPeerHost());
		}
	};
}

2.如果上面的代码还不能通过测试,  那请先检查你的两个p12格式的数据是否正确!秘钥和公钥太多,可能加密的时候搞混了也不一定!


遇到问题慢慢查,多在stack overflow上找答案,早晚会弄出来的,我当时也折腾了几个小时吧!

希望对你有帮助,手写不易,若是帮到你了 点个赞吧!谢谢大笑

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值