
其实2者实现过程是类似的,我对httpclient4.3+的版本比较熟悉,生成httpclient实例的一般过程是:首先生成SSLContext,然后用sslcontext作为参数传入工厂方法生成SSLsocketfactory实例,之后通过HttpClientBuilder()将工厂传进去生成httpclient实例,当然生成工厂实例这一步可以不做,看需求,因为工厂可以设置一些连接参数,如果你用不到可以直接把SSLContext传入HttpClientBuilder()出来httpclient实例。
过程了解了,那么如果要做证书验证,对于单向认证,我们只需要信任服务器证书即可,如果你手里有服务器证书(一般都可以下载),可以直接把它转成keystore格式,然后sslcontext有一个.loadTrustMaterial(xxx.keystore)方法设置证书信任域,你把服务器证书设置进去就可以了,还有一个.loadTrustMaterial(null, new TrustSelfSignedStrategy()),这是默认信任所有,当然不太安全,另外还可以通过重写默认方法信任所有证书,这个不再赘述,你选择一种方法就行。
对于双向认证,你只需要把客户端证书传过去即可,你手上肯定有客户端证书对吧,把它整成keystore格式,然后通过sslcontext的.loadKeyMaterial(xx.keystore,"password")把证书传进去,很简单吧,下面我给你个例子,是我以前写的,也参考了网上的例子。
这个是先得到keystore实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class TrustKey {
@SuppressWarnings("finally")
public static KeyStore getTrustKey() {
KeyStore trustStore = null
FileInputStream fis = null
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType())
//fis = new FileInputStream(new File("D:\\java\\tomcat8\\wx_dev\\webapps\\data.keystore"))
fis = new FileInputStream(new File("E:\\certi\\data.keystore"))
trustStore.load(fis, "password".toCharArray())//加载KeyStore
} catch (NoSuchAlgorithmException e) {
e.printStackTrace()
} catch (CertificateException e) {
e.printStackTrace()
} catch (IOException e) {
e.printStackTrace()
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace()
} finally {
try {
fis.close()
} catch (IOException e) {
e.printStackTrace()
}
return trustStore
}
}
下面是生成httpclient实例,用到了连接池,如果你不需要可以去掉。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public static CloseableHttpClient getHttpClientResponse() {
CloseableHttpClient httpclient = null
try {
KeyStore trustStore = TrustKey.getTrustKey()//获得keystore
//设置ssl上下文
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(trustStore, "sinowel".toCharArray())
.setSecureRandom(new SecureRandom())
.useSSL()
.build()
ConnectionSocketFactory plainSocketFactory = PlainConnectionSocketFactory.INSTANCE
//将参数注入sslconnection工厂,,忽略域名一致验证
SSLConnectionSocketFactory sslSocketFactoy = new SSLConnectionSocketFactory(
sslContext, new String[]{"TLSv1"}, null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
//注册协议
Registry<ConnectionSocketFactory>r = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainSocketFactory)
.register("https", sslSocketFactoy)
.build()
HttpHost target = new HttpHost(IP, PORT, "https")
//根据已生成协议工厂对象生成连接管理器
connectionManager = new PoolingHttpClientConnectionManager(r)
connectionManager.setMaxTotal(MAXCONNECTION)
//设置每个Route的连接最大数
connectionManager.setDefaultMaxPerRoute(DEFAULTMAXCONNECTION)
//设置指定域的连接最大数
connectionManager.setMaxPerRoute(new HttpRoute(target), 20)
//返回HTTPCLIENT对象
httpclient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setProxy(new HttpHost("10.182.22.88", 8002))
.build()
//将ssl上下文及连接管理器注入工厂产生httpclient对象
//SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext)
//httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()
//httpclient = HttpClientBuilder.create().setSSLSocketFactory(sslsf).build()
} catch (Exception e) {
e.printStackTrace()
} finally {
return httpclient
}
}
你那个 SSLSocketFactory(ks) 是自己的类?你有用过 KeyManager.init (...)? 和 TrustManager.init(...) ?
想要在连接建立过程上交互式的d出确认对话框来的话需要我们自己提供一个 KeyManager 和 TrustManager 的实现类,这有点复杂,你可以看一个 Sun 的 X509KeyManager 是怎么做的,默认地情况下它是从自动搜索匹配的 subject ,我们需要用自己提供的方式d出确认的过程还不是全自动,另外一个账户可能有多个数字证书,比如支付宝我们就有多个签发时间不一样的数字证书,在连接建立时 IE 会提示我们选择其中的一个来使用,银行的 U 盾在安装多张数字证书时也会提示我们选择其中一个对应到你正在使用的yhk号的那张证书。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)