您的位置:首页 > 理论基础 > 计算机网络

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

2016-01-11 19:58 701 查看
在公司用习惯了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() {

@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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: