Android:Https跳过证书验证、Https使用证书、HttpClient、
2016-01-11 19:58
701 查看
在公司用习惯了Http请求,突然要用到Https请求,因为突然换了我太不习惯,在第三方网络请求发现无用时,我开始使用原生的网络请求,突然发现完全不会Https请求。结果一段时间的总结与使用,我把这期间的使用心得发布到csdn,为了是总结知识点和广大程序猿方便。
既然叫跳过证书验证,那么我们在使用网络请求之前,就应该使用一定的手段来跳过验证。
1、首先得重写org.apache.http.conn.ssl.SSLSocketFactory这个类,从字面意思理解就是:加密套接字协议层工厂。
接下来就一步一步完成。
很多东西我是通过倒推查看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
a6a9
.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() {
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public 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 block
e.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、首先得重写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() { @Override public X509Certificate[] getAcceptedIssuers() { // TODO Auto-generated method stub return null; } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { // TODO Auto-generated method stub } @Override public 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 block e.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
a6a9
.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() {
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public 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 block
e.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();
}
}
相关文章推荐
- 虚拟机VMware3种网络模式(桥接、nat、Host-only)的工作原理
- 使用套接字Socked实现网络通讯(网络编程)
- 【解决方案】Http请求报错
- 从僵尸网络追踪到入侵检测 第6章 Honeyd日志使用
- 关于http接口防止非法调用的设计方案
- 网络通信的工作原理
- 反向传播神经网络 BPNN
- OpenCV中使用神经网络 CvANN_MLP
- BZOJ 1189: [HNOI2007]紧急疏散evacuate|网络流|二分答案
- 使用okhttp异步下载图片,保存到本地,并在系统相册中显示
- iOS开发网络篇之文件下载、大文件下载、断点下载
- 从僵尸网络追踪到入侵检测 第5章 使用Honeyd创建防御路由模板
- avaweb学习总结(八)——HttpServletResponse对象(二)
- ios 中使用https的知识
- [转载]Fiddler监控任意APK的HTTPS请求
- C++ 用libcurl库进行http通讯网络编程
- 从ZooKeeper源代码看如何实现分布式系统(三)高性能的网络编程
- C# post请求 HttpWebRequest
- centos6下httpd2.2的配置
- Android网络请求框架:Android-async-http简单使用