最近笔者公司有需要用到https协议的方式来做项目,所以记录一下,希望以后能回顾一下
什么是https协议,在这里我也不详细说明,你可以去了解一下
1.我们先分析一下,如果我们需要用到https,有哪些地方需要做处理
1)Retrofit 请求服务数据
Retrofit 中的证书锁定同样是借助OkHttpClient实现的:通过为OkHttpClient添加CertificatePinner即可。CertificatePinner对象以构建器的方式创建,可以通过其add()方法来锁定多个证书。
public class OkHttpClientManager {
public static void setCertificates( 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) {
}
}
// SSLContext sslContext = SSLContext.getInstance("TLS");
//
// TrustManagerFactory trustManagerFactory =
// TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//
// trustManagerFactory.init(keyStore);
// sslContext.init
// (
// null,
// trustManagerFactory.getTrustManagers(),
// new SecureRandom()
// );
// mOkHttpClient.sslSocketFactory(sslContext.getSocketFactory());
//
//
} catch (Exception e) {
e.printStackTrace();
}
}
//获取这个SSLSocketFactory
public static SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, getTrustManager(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//获取TrustManager
private static TrustManager[] getTrustManager() {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
}
};
return trustAllCerts;
}
//获取HostnameVerifier
public static HostnameVerifier getHostnameVerifier() {
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
return hostnameVerifier;
}
}
【Application】
@Override
public void onCreate() {
super.onCreate();
try {
OkHttpClientManager.setCertificates(getAssets().open("AlphaSSLRootCA.cer"), getAssets().open("mediadRootCA.cer"));
} catch (IOException e) {
e.printStackTrace();
}
}
【在请求服务前调用认证证书】
public static OkHttpClient defaultOkHttpClient() {
OkHttpClient.Builder mOkHttpClient = new OkHttpClient.Builder();
mOkHttpClient.sslSocketFactory(OkHttpClientManager.getSSLSocketFactory());//添加证书
mOkHttpClient.writeTimeout(30 * 1000, TimeUnit.MILLISECONDS);
mOkHttpClient.readTimeout(10 * 1000, TimeUnit.MILLISECONDS);
mOkHttpClient.connectTimeout(10 * 1000, TimeUnit.MILLISECONDS);
//设置缓存路径
File httpCacheDirectory = new File(app.getCacheDir(), "okhttpCache");
//设置缓存 10M
Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
mOkHttpClient.cache(cache);
//设置拦截器
mOkHttpClient.addInterceptor(LoggingInterceptor);
mOkHttpClient.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR);
mOkHttpClient.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR);
return mOkHttpClient.build();
}
2)Glide 图片加载
Glide 使用的自己的网络请求来加载的图片,想要用glide访问https图片,就必须替换掉glide原始加载图片的方法,使其同样做到信任所有证书。
首先重新GlideModule,ModelLoader,DataFetcher
【DataFetcher】
public class OkHttpStreamFetcher implements DataFetcher<InputStream> {
private final OkHttpClient client;
private final GlideUrl url;
private InputStream stream;
private ResponseBody responseBody;
public OkHttpStreamFetcher(OkHttpClient client, GlideUrl url) {
this.client = client;
this.url = url;
}
@Override
public InputStream loadData(Priority priority) throws Exception {
Request.Builder requestBuilder = new Request.Builder()
.url(url.toStringUrl());
for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
Response response = client.newCall(request).execute();
responseBody = response.body();
if (!response.isSuccessful()) {
throw new IOException("Request failed with code: " + response.code());
}
long contentLength = responseBody.contentLength();
stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
return stream;
}
@Override
public void cleanup() {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
if (responseBody != null) {
responseBody.close();
}
}
@Override
public String getId() {
return url.getCacheKey();
}
@Override
public void cancel() {
}
}
【ModelLoader】
public class OkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> {
public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
private static volatile OkHttpClient internalClient;
private OkHttpClient client;
private static OkHttpClient getInternalClient() {
if (internalClient == null) {
synchronized (Factory.class) {
if (internalClient == null) {
internalClient = new OkHttpClient();
}
}
}
return internalClient;
}
public Factory() {
this(getInternalClient());
}
public Factory(OkHttpClient client) {
this.client = client;
}
@Override
public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
return new OkHttpUrlLoader(client);
}
@Override
public void teardown() {
}
}
private final OkHttpClient client;
public OkHttpUrlLoader(OkHttpClient client) {
this.client = client;
}
@Override
public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
return new OkHttpStreamFetcher(client, model);
}
}
【GlideModule】
public class OkHttpGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
// Do nothing.
}
@Override
public void registerComponents(Context context, Glide glide) {
OkHttpClient mHttpClient = new OkHttpClient().newBuilder()
.sslSocketFactory(OkHttpClientManager.getSSLSocketFactory())
.hostnameVerifier(OkHttpClientManager.getHostnameVerifier())
.build();
glide.register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(mHttpClient));
}
}
【AndroidManifes.xml】
<meta-data
android:name="包名.OkHttpGlideModule"
android:value="GlideModule" />
3)WebView 数字证书
WebView组件加载网页发生证书认证错误时,会调用WebViewClient类的onReceivedSslError方法,在这个方法里,可以点击源码看到SslErrorHandler中有两个主要的方法(我这里使用了Tencent X5 浏览器)
cancel( )
停止加载问题页面
proceed( )
忽略SSL证书错误,继续加载页面(不推荐)
既然用到了https,我们大部分时候都是为了网络安全问题
所以,可以定义一个类来验证证书安全
//获取webz证书
private static OkHttpClient.Builder setWebCertificates(OkHttpClient.Builder client) {
try {
SSLSocketFactory sslSocketFactory = OkHttpClientManager.getSSLSocketFactory();
X509TrustManager trustManager = Platform.get().trustManager(sslSocketFactory);
client.sslSocketFactory(sslSocketFactory, trustManager);
} catch (Exception e) {
e.printStackTrace();
}
return client;
}
// 验证证书
public static void webCertificateOfVerification(final SslErrorHandler handler, String url) {
OkHttpClient.Builder builder = OkHttpClientManager.setWebCertificates(new OkHttpClient.Builder());
Request request = new Request.Builder().url(url)
.build();
builder.build().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("验证失败", e.getMessage());
handler.cancel();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("验证成功", response.body().string());
handler.proceed();
}
});
}
onReceivedSslError中的代码
private WebViewClient client = new WebViewClient() {
/**
* 防止加载网页时调起系统浏览器
*/
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
/**
* 处理ssl
* @param webView
* @param sslErrorHandler
* @param sslError
*/
@Override
public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
OkHttpClientManager.webCertificateOfVerification(sslErrorHandler, webView.getUrl());
}
};
本文结合大神的文章以及自己的理解,有问题欢迎指出,共同学习