ohttp请求https的认证

参考文章

Android Https相关完全解析 当OkHttp遇到Https
Aandroid中https请求的单向认证和双向认证
okhttp实现https请求

以上文章都有说明单向认证和双向认证的方法

最后参考了开源项目
okhttputils

初始化okhttp时添加以下设置

addUnSafeSslSocketAndHostnameVerifier信任所有证书不做校验(大部分简单项目做法)
/**
 * 通过所有https的认证。不做判断,不安全
 * @param builder
 * @return
 */
private static Builder addUnSafeSslSocketAndHostnameVerifier(Builder builder) {
    //如果设置了sslSocketFactory却没有配置对应的hostnameVerifier,那么Https请求是无法成功的
    //不设置会报:javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    HttpsSslFactroy.SSLParams sslParams = HttpsSslFactroy.getSslSocketFactory(); //获取默认的SSLParams,通过所有认证
    addSSLSocketFactory(builder, sslParams.mSSLSocketFactory, sslParams.mTrustManager);

    //不设置请求https会报错:javax.net.ssl.SSLPeerUnverifiedException: Hostname xxx地址的host not verified:
    //设置ip授权认证:如果已经安装该证书,可以不设置,否则需要设置??????????????不设置会报错。。。待处理
    HostnameVerifier hostnameVerifier = HttpsSslFactroy.getHostnameVerifierUnSafe();
    return addHostnameVerifier(builder, hostnameVerifier);
}

/**
 * 单向认证
 * @param builder
 * @param context
 * @param certificates 服务器需要验证的证书 把证书放到raw目录下
 * @return
 */
public static Builder addSSLSocketFactory(Builder builder, Context context, @RawRes int[] certificates) {
    HttpsSslFactroy.SSLParams sslParams = HttpsSslFactroy.getSslSocketFactory(context, certificates);
    return addSSLSocketFactory(builder, sslParams.mSSLSocketFactory, sslParams.mTrustManager);
}

/**
 * 双向认证
 * @param builder
 * @param context
 * @param certificates 服务器需要验证的证书 把证书放到raw目录下
 * @param clientKeyStoreBksFile 本地验证证书。一般双向验证才需要 把证书放到raw目录下
 * @param password 本地验证证书的密码
 * @return
 */
public static Builder addSSLSocketFactory(Builder builder, Context context, @RawRes int[] certificates, @RawRes int clientKeyStoreBksFile, String password) {
    HttpsSslFactroy.SSLParams sslParams = HttpsSslFactroy.getSslSocketFactory(context, certificates, clientKeyStoreBksFile, password);
    return addSSLSocketFactory(builder, sslParams.mSSLSocketFactory, sslParams.mTrustManager);
}

/**
 * 双向认证
 * @param builder
 * @param certificates 服务器需要验证的证书 把证书放到raw目录下
 * @param bksFile 本地验证证书。一般双向验证才需要 把证书放到raw目录下
 * @param password 本地验证证书的密码
 * @return
 */
public static Builder addSSLSocketFactory(Builder builder, InputStream[] certificates, InputStream bksFile, String password) {
    HttpsSslFactroy.SSLParams sslParams = HttpsSslFactroy.getSslSocketFactory(certificates, bksFile, password);
    return addSSLSocketFactory(builder, sslParams.mSSLSocketFactory, sslParams.mTrustManager);
}


public static Builder addSSLSocketFactory(Builder builder, SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
    builder.sslSocketFactory(sslSocketFactory, trustManager);
    return builder;
}


//http://www.jianshu.com/p/16994e49e2f6
//http://blog.csdn.net/sk719887916/article/details/51597816
/**
 * 指定支持的host
 * hostnameVerifier对服务端返回的一些信息进行相关校验,用于客户端判断所连接的服务端是否可信,通常默认return true,或者简单校验hostname是否正确,默认不使用的话会调用okhttp的OkHostnameVerifier:
 https://www.jianshu.com/p/1373889e74b2
 * @param builder
 * @param hosts 指定支持的host
 * @return
 */
public static Builder addHostnameVerifier(Builder builder, String[] hosts) {
    HostnameVerifier hostnameVerifier = HttpsSslFactroy.getHostnameVerifierSafe(hosts);
    return addHostnameVerifier(builder, hostnameVerifier);
}


public static Builder addHostnameVerifier(Builder builder, HostnameVerifier hostnameVerifier) {
    builder.hostnameVerifier(hostnameVerifier);
    return builder;
}

添加 HttpsSslFactroy .jva

 /**
     * 参考github项目okhttputils
     * https://github.com/hongyangAndroid/okhttputils
     * 

* 服务器端需要验证的客户端证书,其实就是客户端的keystore * 1、设置可访问所有的https网站 * HttpsSslFactroy.SSLParams sslParams = HttpsSslFactroy.getSslSocketFactory(null, null, null); *

* 2、设置具体的证书 * HttpsSslFactroy.SSLParams sslParams = HttpsSslFactroy.getSslSocketFactory(服务器证书的inputstream, null, null); *

* 3、双向认证 * HttpsSslFactroy.getSslSocketFactory(服务器证书的inputstream, 本地证书的inputstream,本地证书的密码) *

* 使用 * new OkHttpClient.Builder().sslSocketFactory(sslParams.mSSLSocketFactory, sslParams.mTrustManager)).build(); */ public class HttpsSslFactroy { public static class SSLParams { public SSLSocketFactory mSSLSocketFactory; public X509TrustManager mTrustManager; } /** * 默认通过人所有证书 * @return */ public static SSLParams getSslSocketFactory() { return getSslSocketFactory(null, null, null); } /** * 单向认证 * @param context * @param certificates 服务器需要验证的证书 把证书放到raw目录下 * @return */ public static SSLParams getSslSocketFactory(Context context, @RawRes int[] certificates) { InputStream[] certificatesInputStream = getInputStreamOfRaw(context, certificates); return getSslSocketFactory(certificatesInputStream, null, null); } /** * 双向认证 * @param context * @param certificates 服务器需要验证的证书 把证书放到raw目录下 * @param clientKeyStoreBksFile 本地验证证书。一般双向验证才需要 把证书放到raw目录下 * @param password 本地验证证书的密码 * @return */ public static SSLParams getSslSocketFactory(Context context, @RawRes int[] certificates, @RawRes int clientKeyStoreBksFile, String password) { InputStream[] certificatesInputStream = getInputStreamOfRaw(context, certificates); InputStream clientKeyStoreIs = context.getResources().openRawResource(clientKeyStoreBksFile); return getSslSocketFactory(certificatesInputStream, clientKeyStoreIs, password); } /** * @param certificates 服务器证书 * @param bksFile 客户端证书文件 * @param password 客户端证书密码 * @return */ public static SSLParams getSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password) { SSLParams sslParams = new SSLParams(); try { //双向认证- 验证客户端证书-通过本地证书和密码本地认证的keyManagers KeyManager[] keyManagers = prepareKeyManager(bksFile, password); //单向认证-只验证服务器证书 TrustManager[] trustManagers = prepareTrustManager(certificates); X509TrustManager trustManager; if (trustManagers != null) { trustManager = new MyTrustManager(chooseTrustManager(trustManagers)); } else { trustManager = new UnSafeTrustManager(); //不校验、认证所有证书 } //初始化SSLContext实例 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagers, new TrustManager[]{trustManager}, null); //设置对外使用的参数 sslParams.mSSLSocketFactory = sslContext.getSocketFactory(); sslParams.mTrustManager = trustManager; return sslParams; } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); } catch (KeyManagementException e) { throw new AssertionError(e); } catch (KeyStoreException e) { throw new AssertionError(e); } } private static TrustManager[] prepareTrustManager(InputStream... certificates) { if (certificates == null || certificates.length <= 0) { return null; } try { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); //使用默认证书 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); //去掉系统默认证书 keyStore.load(null); int index = 0; //遍历证书 for (InputStream certificate : certificates) { String certificateAlias = Integer.toString(index++); //设置自己的证书 keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate)); try { if (certificate != null) { certificate.close(); } } catch (IOException e) { } } //通过信任管理器获取一个默认的算法 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); //算法工厂创建 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm); trustManagerFactory.init(keyStore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); return trustManagers; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * Java平台默认识别jks格式的证书文件,但是android平台只识别bks格式的证书文件。所以导入的流应该是bks的文件 * * @param bksFile * @param password * @return */ private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) { try { if (bksFile == null || password == null) return null; KeyStore clientKeyStore = KeyStore.getInstance("BKS"); clientKeyStore.load(bksFile, password.toCharArray()); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(clientKeyStore, password.toCharArray()); return keyManagerFactory.getKeyManagers(); } catch (KeyStoreException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnrecoverableKeyException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) { for (TrustManager trustManager : trustManagers) { if (trustManager instanceof X509TrustManager) { return (X509TrustManager) trustManager; } } return null; } private static class MyTrustManager implements X509TrustManager { private X509TrustManager defaultTrustManager; private X509TrustManager localTrustManager; public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException { TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); var4.init((KeyStore) null); defaultTrustManager = chooseTrustManager(var4.getTrustManagers()); this.localTrustManager = localTrustManager; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { defaultTrustManager.checkServerTrusted(chain, authType); } catch (CertificateException ce) { localTrustManager.checkServerTrusted(chain, authType); } } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } private static class UnSafeTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[]{}; } } /** * https请求才会判断获取host校验HostnameVerifier * 信任所有host */ public static HostnameVerifier getHostnameVerifierUnSafe() { HostnameVerifier hostnameVerifier = new HostnameVerifier() { /** * @param hostname 请求地址的host * @param session 包括了从服务端返回的证书链 */ @Override public boolean verify(String hostname, SSLSession session) { Log.i("lch", "证书校验:" + hostname); return true; } }; return hostnameVerifier; } /** * 获取host校验HostnameVerifier * 需要校验host * {@link HostnameVerifier} * 有证书认证,貌似不用设置这个 * hostnameVerifier则是对服务端返回的一些信息进行相关校验的地方,用于客户端判断所连接的服务端是否可信,通常默认return true,或者简单校验hostname是否正确,默认不使用的话会调用okhttp的OkHostnameVerifier: */ public static HostnameVerifier getHostnameVerifierSafe(final String[] hostUrls) { HostnameVerifier hostnameVerifier = new HostnameVerifier() { /** * @param hostname 请求地址的host * @param session 包括了从服务端返回的证书链 */ @Override public boolean verify(String hostname, SSLSession session) { boolean ret = false; for (String host : hostUrls) { if (host.equalsIgnoreCase(hostname)) { ret = true; } } return ret; } }; return hostnameVerifier; } public static InputStream[] getInputStreamOfRaw(Context context, @RawRes int[] certificates) { InputStream[] certificatesInputStream = null; if (certificates != null && certificates.length > 0) { certificatesInputStream = new InputStream[]{}; for (int i = 0; i < certificates.length; i++) { certificatesInputStream[i] = context.getResources().openRawResource(certificates[i]); } } return certificatesInputStream; } }

你可能感兴趣的:(ohttp请求https的认证)