您的当前位置:首页正文

Android Okhttp3添加https自签名证书以及Glide4

2024-11-17 来源:个人技术集锦
  • 将服务端提供的证书文件放到assets文件夹里面,然后获取。(因为是在assets文件下,所以会写入到apk里面)
  • 打开证书文件,将证书里面的内容以字符串的形式通过流写入。(不会写入到apk中)

2.创建秘钥,添加证书进去

3.创建信任管理器,并把秘钥初始化到信任管理器里

4.获取SLL上下文,并把信任管理器初始化到SSL里

5.获取socket工厂,设置到okhttpclient中

6.检验主机名

if (UrlConsts.serverUrl.contains(“https://”)){

InputStream cerInputStream = null;

try {

//方式一:在assets中获取证书

cerInputStream = context.getAssets().open(“ssl.cer”);

//方式二:把字符串通过流的形式获取证书

// cerInputStream = new ByteArrayInputStream(cerText.getBytes(“UTF-8”));

//获取socket工厂

SSLSocketFactory sslSocketFactory = SSLUtil.getSSLSocketFactory(cerInputStream);

//okhttp设置socket工厂

okHttpClientBuilder.sslSocketFactory(sslSocketFactory);

} catch (IOException e) {

e.printStackTrace();

}

}

//检验主机名

okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() {

@Override

public boolean verify(String hostname, SSLSession session) {

return true;

}

});

public class SSLUtil {

/**

  • 返回SSLSocketFactory

  • @param certificates 证书的输入流

  • @return SSLSocketFactory

*/

public static SSLSocketFactory getSSLSocketFactory(InputStream… certificates) {

return getSSLSocketFactory(null,certificates);

}

/**

  • 双向认证

  • @param keyManagers KeyManager[]

  • @param certificates 证书的输入流

  • @return SSLSocketFactory

*/

public static SSLSocketFactory getSSLSocketFactory(KeyManager[] keyManagers, InputStream… certificates) {

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) {

e.printStackTrace();

}

}

//创建信任管理工厂

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

//初始化信任管理器

trustManagerFactory.init(keyStore);

//获取SSL上下文对象

SSLContext sslContext = SSLContext.getInstance(“TLS”);

//初始化信任管理器

sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom());

//获取socket工厂

SSLSocketFactory socketFactory = sslContext.getSocketFactory();

return socketFactory;

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

}

测试运行,完美解决。

2.信任所有证书(不建议使用)

服务端提供的证书文件,如果服务端更改了需要客户端进行相应的更改,否则无法请求服务端数据。如果想不换证书可以继续访问,可以通过X509TrustManager信任所有的证书,以达到客户端不换证书文件就能获取到服务端数据,但不建议这样使用!!!

/**

*信任所有证书(不建议使用)

  • @return

*/

public static SSLSocketFactory getAllSSLSocketFactory(){

//创建X509信任管理器

TrustManager[] trustManagers = new TrustManager[]{

new X509TrustManager() {

@Override

public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

}

@Override

public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

}

@Override

public X509Certificate[] getAcceptedIssuers() {

return new X509Certificate[0];

}

}

};

try {

//获取SSL上下文对象

SSLContext sslContext = SSLContext.getInstance(“TLS”);

//初始化无信任管理器

sslContext.init(null, trustManagers, new SecureRandom());

//获取socket工厂

SSLSocketFactory socketFactory = sslContext.getSocketFactory();

return socketFactory;

} catch (NoSuchAlgorithmException | KeyManagementException e) {

e.printStackTrace();

}

return null;

}

四、Glide4.0以上 添加自签名证书

Glide 直接加载没有权威机构颁发的证书https的URL会直接抛出错误SSLHandshakeException(CertPathValidatorException证书路径验证器异常)

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

看到CertPathValidatorException这个异常,不用多说也知道什么原因导致的,所以我们需要对Glide内部的Okhttp3进行https自签名。

  1. 从Glide官网查到,需 添加Glide需要的依赖

// Glide图片加载库

api ‘com.github.bumptech.glide:glide:4.11.0’

// Glide需要处理注解时的依赖库,用于处理注解并生成java类

annotationProcessor ‘com.github.bumptech.glide:compiler:4.11.0’

// Glide集成OkHttp时需要使用的库

api ‘com.github.bumptech.glide:okhttp3-integration:4.11.0’

  1. 创建一个类继承AppGlideModule并对该类添加GlideModule注解,由Glide的注解处理器自动帮我们处理该类,无需其他操作和配置,添加Https的证书信任,最后替换掉Glide内部的okHttp使用我们自己创建的

//注解处理器帮助我们生成meta-data,无需自行配置

@GlideModule

public class OkHttpGlideModule extends AppGlideModule {

private SSLSocketFactory mSSLSocketFactory;

private X509TrustManager mX509TrustManager;

@Override

public void registerComponents(Context context, Glide glide, Registry registry) {

super.registerComponents(context, glide, registry);

replace(registry);

}

private void replace(Registry registry) {

//信任管理器

mX509TrustManager = new X509TrustManager() {

@Override

public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { }

@Override

public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { }

@Override

public X509Certificate[] getAcceptedIssuers() {

return new X509Certificate[0];

}

};

//构建OkHttpClient.Builder

OkHttpClient.Builder builder = new OkHttpClient.Builder();

try {

//获取SSL上下文对象

SSLContext sslContext = SSLContext.getInstance(“SSL”);

//初始化信任管理器

sslContext.init(null, new TrustManager[]{mX509TrustManager}, new SecureRandom());

//获取Socket工厂

mSSLSocketFactory = sslContext.getSocketFactory();

//OkHttp设置Socket工厂

builder.sslSocketFactory(mSSLSocketFactory, mX509TrustManager);

} catch (NoSuchAlgorithmException | KeyManagementException e) {

e.printStackTrace();

}

//构建OkHttpClient

OkHttpClient okHttpClient = builder.build();

//替换Glide内部的OkHttpClient

registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(okHttpClient));

}

}

  1. 更换Glide为注解处理器生成的GlideApp

GlideApp.with(context).load(url).apply(options).into(imageView);

万事俱备,只需测试,运行跑一下,呃呃呃,尴尬了翻车了…可以看到SSLPeerUnverifiedException异常Hostname 172.17.230.133 not verified,逗我玩了,都已经做认证了凭什么不给我通过,经过百度和对这段话的分析,发现subjectAltName是个空值,大概率猜测会不会是这个值导致的。于是搜索发现:

数字证书使用 Subject 子项标明证书的持有者,并且使用 subjectAltName 扩展项对持有者的身份进行更多的标记和界定,在 subjectAltName 中可以包含有关持有者身份的多条信息。如果证书持有者是一个CA,则 Subject 项不能为空,必须包含一个 DN 名,该 DN 名必须与该 CA 颁发的所有证书中 Issuer 项的 DN 名相同。

只需要在上面代码中添加hostName进行再次验证

//设置主机名进行再次验证

builder.hostnameVerifier(new HostnameVerifier() {

显示全文