什么是HTTPs
https是一种相对安全的传输协议,可以认为是http的安全版本,怎么会安全呢,基础就是靠安全套接字层SSL(Secure Socket Layer),作用
- 认证用户和服务器,确保数据发送到正确的客户机和服务器;(验证证书)
- 加密数据以防止数据中途被窃取;(加密)
- 维护数据的完整性,确保数据在传输过程中不被改变。(摘要算法)
工作原理(转自鸿祥大神的blog)
HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。握手过程的简单描述如下:
浏览器将自己支持的一套加密算法、HASH算法发送给网站。
网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
浏览器获得网站证书之后,开始验证证书的合法性,如果证书信任,则生成一串随机数字作为通讯过程中对称加密的秘钥。然后取出证书中的公钥,将这串数字以及HASH的结果进行加密,然后发给网站。
网站接收浏览器发来的数据之后,通过私钥进行解密,然后HASH校验,如果一致,则使用浏览器发来的数字串使加密一段握手消息发给浏览器。
浏览器解密,并HASH校验,没有问题,则握手结束。接下来的传输过程将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
握手过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私信息的传输。ok,以上的流程不一定完全正确,基本就是这样,当然如果有明显错误欢迎指出。
根据上面的流程,我们可以看到服务器端会有一个证书,在交互过程中客户端需要去验证证书的合法性,对于权威机构颁发的证书当然我们会直接认为合法。对于自己造的证书,那么我们就需要去校验合法性了,也就是说我们只需要让OkhttpClient去信任这个证书就可以畅通的进行通信了。
当然,对于自签名的网站的访问,网上的部分的做法是直接设置信任所有的证书,对于这种做法肯定是有风险的,所以这里我们不去介绍了,有需要自己去查。
应用实例
这里我只是把自己项目中用到的写写。说说思路吧,这里我的网络请求是用的volley实现,用了事件总线otto的框架。
- 1.我用的是Android studio,因此在build.gradle中的buildTypes的debug和release下的buildConfigField都要把url地址改为https的
2.主要的代码都是在RequestController中实现,直接贴代码
package com.zjbl.business.controller; import android.content.Context; import android.util.Log; import com.android.volley.RequestQueue; import com.android.volley.toolbox.HurlStack; import com.android.volley.toolbox.Volley; import com.zjbl.business.BuildConfig; import com.zjbl.business.utils.StringRequestWrapper; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.security.KeyStore; import java.security.SecureRandom; import java.security.cert.CertificateFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; /** * Created by Administrator on 2015/10/22. */ public class RequestController { private static RequestController instance; private RequestQueue mQueue; private static final String DEBUG_CERTIFICATE = "取得证书的内容"; private static final String RELEASE_CERTIFICATE = "取得证书的内容"; private RequestController(Context context) { InputStream inputStream = null; try { if (!BuildConfig.DEBUG){ inputStream = new ByteArrayInputStream(RELEASE_CERTIFICATE.getBytes("UTF-8")); } else { inputStream = new ByteArrayInputStream(DEBUG_CERTIFICATE.getBytes("UTF-8")); } } catch (Exception e){ Log.e("RequestController", "e = "+e.getMessage()+"-----获取证书信息错误"); } mQueue = Volley.newRequestQueue(context, new HurlStack(null, createCertificates(inputStream))); // mQueue = Volley.newRequestQueue(context); } public static RequestController getRequestControllerInstance(Context context){ if (instance == null){ synchronized (RequestController.class){ if (instance == null){ instance = new RequestController(context); } } } return instance; } public RequestQueue getQueue(){ return mQueue; } public void request(StringRequestWrapper stringRequestWrapper){ mQueue.add(stringRequestWrapper.stringRequest); } /** 构造CertificateFactory对象,通过它的generateCertificate(is)方法得到Certificate。 // 然后讲得到的Certificate放入到keyStore中。 // 接下来利用keyStore去初始化我们的TrustManagerFactory // 由trustManagerFactory.getTrustManagers获得TrustManager[]初始化我们的SSLContext // 最后,sslSocketFactory即可 */ public SSLSocketFactory createCertificates(InputStream... certificates) { SSLSocketFactory sslSocketFactory = null; try { //CertificateFactory此类定义了用于从相关的编码中生成证书、证书路径 (CertPath) 和证书撤消列表 (CRL) 对象的 CertificateFactory 功能 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() ); Log.e("RequestController", "sslContext = " + sslContext.getProtocol() + "---" + sslContext.getServerSocketFactory() + "---" + sslContext.getSocketFactory() + "----" + sslContext.getDefaultSSLParameters()); sslSocketFactory = sslContext.getSocketFactory(); } catch (Exception e) { e.printStackTrace(); } finally { return sslSocketFactory; } } }
总结
上面的代码主要对https的操作都在createCertificates方法中,然后在RequestController(content)方法中实例化整个volley队列,一般使用时需要具体的去继承该类然后在对应的类中实现对应的方法,在其他页面调用,会是如下的用法:
RequestController.getRequestControllerInstance(this.getActivity()).request(requestWrapper);
还有另外一种调用方法,新建一个controller,然其他类去继承该类,而该controller中具体的代码:
public class Controller { protected Context context; protected RequestQueue mQueue; protected Controller(BackgroundBus backgroundBus, Context context) { backgroundBus.register(this); this.context=context; mQueue = RequestController.getRequestControllerInstance(context).getQueue(); // mQueue = Volley.newRequestQueue(context); } public void request(StringRequestWrapper stringRequestWrapper){ mQueue.add(stringRequestWrapper.stringRequest); } }