关于Https的双向认证问题

      最近做了个项目要求使用https的双向认证,我第一次做我也很懵逼啊,不会做只能找百度,于是乎百度了一大堆资料。。。

首先呢我们需要两个证书:

1.客户端证书

2.服务端证书 

        这两个证书都由后台生成之后给我们,当然记得让后台转化为BKS格式的,android独有的。

拿到证书之后就要配置我们的网络环境了。ok直接上代码

我的网络请求使用的是 Retrofit所以要先配置okhttp 

Retrofit retrofit;
  OkHttpClient client = new OkHttpClient.Builder()
                        .sslSocketFactory(getSSLCertifcation())//获取SSLSocketFactory
                        .hostnameVerifier(new UnSafeHostnameVerifier())//添加hostName验证器
                        .connectTimeout(10, TimeUnit.SECONDS)
                        .writeTimeout(10, TimeUnit.SECONDS)
                        .readTimeout(1, TimeUnit.MINUTES)
                        .addInterceptor(new Interceptor() {
                            @Override
                            public Response intercept(@NonNull Chain chain) throws IOException {
                                Request original = chain.request();

                                Request request = original.newBuilder()
                                        .header("Authorization", HttpConfig.Token)
                                        .method(original.method(), original.body())
                                        .build();

                                return chain.proceed(request);
                            }
                        }).build();
retrofit = new Retrofit.Builder()
        .baseUrl(api)
        .client(client)
        .addConverterFactory(FastJsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build();

下面是我使用的client的方法类

private final static String CLIENT_PRI_KEY = "client.bks";//证书名字
private final static String TRUSTSTORE_PUB_KEY = "client_truststore.bks";//证书名字
private final static String CLIENT_BKS_PASSWORD = "xxxx";//证书密码
private final static String TRUSTSTORE_BKS_PASSWORD = "xxxx";//证书密码
private final static String KEYSTORE_TYPE = "BKS";
private final static String PROTOCOL_TYPE = "TLS";
private final static String CERTIFICATE_FORMAT = "X509";
  public static SSLSocketFactory getSSLCertifcation() {
        SSLSocketFactory sslSocketFactory = null;
        try {
            // 服务器端需要验证的客户端证书,其实就是客户端的keystore
            KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);// 客户端信任的服务器端证书
            KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE);//读取证书

            InputStream ksIn = APP.appOS.getAssets().open(CLIENT_PRI_KEY);
            InputStream tsIn = APP.appOS.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_FORMAT);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_FORMAT);
            trustManagerFactory.init(trustStore);
            keyManagerFactory.init(keyStore, CLIENT_BKS_PASSWORD.toCharArray());
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
            sslSocketFactory = sslContext.getSocketFactory();
        } 
        catch (IOException | CertificateException | NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            e.printStackTrace();
        }
        return sslSocketFactory;
    }
static class UnSafeHostnameVerifier implements HostnameVerifier {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        Log.e("ssl",hostname);
        Log.e("ssl",session.toString());
        return true;//自行添加判断逻辑,true->Safe,false->unsafe
    }
}

这样我们https双向认证就解决了。

 

 

 

 

你可能感兴趣的:(网络请求)