Android:Https跳过证书验证、Https使用证书、HttpClient、

来源:互联网 发布:51单片机控制步进电机 编辑:程序博客网 时间:2024/06/10 03:11

在公司用习惯了Http请求,突然要用到Https请求,因为突然换了我太不习惯,在第三方网络请求发现无用时,我开始使用原生的网络请求,突然发现完全不会Https请求。结果一段时间的总结与使用,我把这期间的使用心得发布到csdn,为了是总结知识点和广大程序猿方便。


既然叫跳过证书验证,那么我们在使用网络请求之前,就应该使用一定的手段来跳过验证。

1、首先得重写org.apache.http.conn.ssl.SSLSocketFactory这个类,从字面意思理解就是:加密套接字协议层工厂。
2、必须用到TrustManager 就是证书管理者。
3、最后就是要用到安全协议的实现类:SSLContext

接下来就一步一步完成。

1、直接继承SSLSocketFactory

public class SSLHttpsUtils extends SSLSocketFactory{/** * @param truststore * @throws NoSuchAlgorithmException * @throws KeyManagementException * @throws KeyStoreException * @throws UnrecoverableKeyException */public SSLHttpsUtils(KeyStore truststore) throws NoSuchAlgorithmException,KeyManagementException, KeyStoreException,UnrecoverableKeyException {super(truststore);}}

2、通过官方API发现原来TrustManager里面没有任何内容,只有一个间接子类X509TrustManager,通过网上查看,X509是一个通用的证书格式,只需要拿到这个一个格式就OK了。

TrustManager manager = new X509TrustManager() {@Overridepublic X509Certificate[] getAcceptedIssuers() {// TODO Auto-generated method stubreturn null;}@Overridepublic void checkServerTrusted(X509Certificate[] arg0, String arg1)throws CertificateException {// TODO Auto-generated method stub}@Overridepublic void checkClientTrusted(X509Certificate[] arg0, String arg1)throws CertificateException {// TODO Auto-generated method stub}};

3、最后把这些东西融合到一起就要用到SSLContext,通过API发现通过SSLContext.getInstance,这里我们就取最简单的,里面传参发现一个不认识的参数通过查找是一个指定的安全协议:TLS三次握手协议,最后通过init初始化这个安全协议,再把这个方法放在SSLSocketFactory的构造函数中。

<pre name="code" class="java">private SSLContext context = SSLContext.getInstance("TLS");private void initSSLContext() {try {// 既然是跳过认证,我们把没有的都填null,此时发现第二个参数是一个数组,那么意思就是我们可以放多个证书认证;context.init(null, new TrustManager[] { manager }, null);} catch (KeyManagementException e) {// TODO Auto-generated catch blocke.printStackTrace();}}


4、以上工作做完我们就开始使用这些东西,并得到我们想要的。

public static DefaultHttpClient getNewHttpClient() {try {// 查看API这里可以得到一个默认的Type.KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());// 这里发现需要一个KeyStore,那么我们就在上面New一个KeyStore,这是一个密钥库,查看API发现能直接getInstance得到对象;SSLSocketFactory factory = new SSLHttpsUtils(truststore);// 这里就是我们最需要的也是最关键的一步,设置主机认证,通过API发现有一个常量就是允许所有认证通过。factory.setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER);// 实现Httpprams的子类HttpParams params = new BasicHttpParams();//通过Http适配器设置必要参数,现在通用HTTP1.1协议,和UTF-8字符。HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);//通过适配器设置连接参数,等待时间和,连接时间HttpConnectionParams.setSoTimeout(params, 10000);HttpConnectionParams.setConnectionTimeout(params, 5000);// 同样New出来,查看API,需要我们注册一个计划,来封装协议细节SchemeRegistry schreg = new SchemeRegistry();// 最后一个参数是端口设置,Https常用的端口就是443。schreg.register(new Scheme("https", factory, 443));// 既然是工具类,这里也把http协议加上,中间的协议工厂我们就用简单的PlainSocketFactory,这里可以通过API查看到,端口就用常用的80端口(默认)schreg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));// ClientConnectionManager是一个借口,就实现他的子类,同样需要2个参数,第一个我们熟悉,第二个就是让我们自定义自己的一套方案协议,继续在上面一步一步完成;ClientConnectionManager conman = new SingleClientConnManager(params, schreg);// 返回我们需要的一个默认Httpclient,为了把之前做的关联起来,就new最多参数的构造函数,需要2个参数,Httpparams是我们熟悉的,// 发现ClientConnectionManager不太熟悉,通过API发现这是客服端连接管理者,既然这样,就在上面一步一步完成。return new DefaultHttpClient(conman, params);} catch (Exception e) {// TODO: handle exception}return new DefaultHttpClient();}

很多东西我是通过倒推查看API来完成的,如果没看懂,可以先通看一次,然后再倒推回去看。

最后附上完整代码:

/** * @author 李飞翔 * @ SSLHttpsUtils.java * 时间:2016-1-11 下午8:03:05 * */package com.example.boketestapplication;import java.security.KeyManagementException;import java.security.KeyStore;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.UnrecoverableKeyException;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import javax.net.ssl.SSLContext;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;import org.apache.http.HttpVersion;import org.apache.http.conn.ClientConnectionManager;import org.apache.http.conn.scheme.PlainSocketFactory;import org.apache.http.conn.scheme.Scheme;import org.apache.http.conn.scheme.SchemeRegistry;import org.apache.http.conn.ssl.SSLSocketFactory;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.impl.conn.SingleClientConnManager;import org.apache.http.params.BasicHttpParams;import org.apache.http.params.HttpConnectionParams;import org.apache.http.params.HttpParams;import org.apache.http.params.HttpProtocolParams;import org.apache.http.protocol.HTTP;/** * @author 李飞翔 * @name SSLHttpsUtils.java * @data 2016-1-11 下午8:03:05 * @TODO */public class SSLHttpsUtils extends SSLSocketFactory {/** * @param truststore * @throws NoSuchAlgorithmException * @throws KeyManagementException * @throws KeyStoreException * @throws UnrecoverableKeyException */public SSLHttpsUtils(KeyStore truststore) throws NoSuchAlgorithmException,KeyManagementException, KeyStoreException,UnrecoverableKeyException {super(truststore);initSSLContext();}TrustManager manager = new X509TrustManager() {@Overridepublic X509Certificate[] getAcceptedIssuers() {// TODO Auto-generated method stubreturn null;}@Overridepublic void checkServerTrusted(X509Certificate[] arg0, String arg1)throws CertificateException {// TODO Auto-generated method stub}@Overridepublic void checkClientTrusted(X509Certificate[] arg0, String arg1)throws CertificateException {// TODO Auto-generated method stub}};private SSLContext context = SSLContext.getInstance("TLS");private void initSSLContext() {try {// 既然是跳过认证,我们把没有的都填null,此时发现第二个参数是一个数组,那么意思就是我们可以放多个证书认证;context.init(null, new TrustManager[] { manager }, null);} catch (KeyManagementException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static DefaultHttpClient getNewHttpClient() {try {// 查看API这里可以得到一个默认的Type.KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());// 这里发现需要一个KeyStore,那么我们就在上面New一个KeyStore,这是一个密钥库,查看API发现能直接getInstance得到对象;SSLSocketFactory factory = new SSLHttpsUtils(truststore);// 这里就是我们最需要的也是最关键的一步,设置主机认证,通过API发现有一个常量就是允许所有认证通过。factory.setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER);// 实现Httpprams的子类HttpParams params = new BasicHttpParams();//通过Http适配器设置必要参数,现在通用HTTP1.1协议,和UTF-8字符。HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);//通过适配器设置连接参数,等待时间和,连接时间HttpConnectionParams.setSoTimeout(params, 10000);HttpConnectionParams.setConnectionTimeout(params, 5000);// 同样New出来,查看API,需要我们注册一个计划,来封装协议细节SchemeRegistry schreg = new SchemeRegistry();// 最后一个参数是端口设置,Https常用的端口就是443。schreg.register(new Scheme("https", factory, 443));// 既然是工具类,这里也把http协议加上,中间的协议工厂我们就用简单的PlainSocketFactory,这里可以通过API查看到,端口就用常用的80端口(默认)schreg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));// ClientConnectionManager是一个借口,就实现他的子类,同样需要2个参数,第一个我们熟悉,第二个就是让我们自定义自己的一套方案协议,继续在上面一步一步完成;ClientConnectionManager conman = new SingleClientConnManager(params, schreg);// 返回我们需要的一个默认Httpclient,为了把之前做的关联起来,就new最多参数的构造函数,需要2个参数,Httpparams是我们熟悉的,// 发现ClientConnectionManager不太熟悉,通过API发现这是客服端连接管理者,既然这样,就在上面一步一步完成。return new DefaultHttpClient(conman, params);} catch (Exception e) {// TODO: handle exception}return new DefaultHttpClient();}}









1 0