HttpClient如何访问需要提交客户端证书的SSL服务

1.1 问题背景

自从***一期工程上了CA认证网关之后,在访问受CA认证网关保护的应用子系统时,必须提交客户端证书。那么问题来了,如果是人工(通过IE浏览器)访问子系统自然没问题,访问时会提示选择证书,输入PIN码等等,照做即可。但是如果是应用程序去访问呢?例如,A子系统提供了外部接口程序,由于受到CA认证网关的“保护”,外部程序如何访问A子系统的接口呢?

1.2 问题分析

应用程序自然没法像人工一样,借助浏览器访问应用子系统。此时外部应用程序如果直接通过HttpGet或HttpPost去访问应用子系统的接口时,会抛异常。

由于上了CA认证网关之后,实现的是应用系统访问的双向身份认证,即:客户端须验证服务端的身份,服务端也须验证客户端的身份。为了实现双向身份认证,客户端须安装服务端提供的服务端证书,并且客户端在访问服务端时须提交客户端证书。只有这样才能实现应用系统的正常访问。对于人工访问是如此,对于应用程序访问亦是如此。

令人庆幸的是,ApacheHttpClient提供了基于双向认证机制访问SSL服务的支持。HttpClient通过自定义一个携带证书的SSL连接,实现对需双向认证的服务的访问。

1.3 解决方案

1.3.1 准备工作

结合当前案例的实际情况,有一些准备工作要做:

1、    制作客户端带私钥的软证书,并转化成JKS格式。操作步骤如下:

1)、在用户管理中心注册用户,并推送到证书注册中心;

2)、登录证书注册中心,首先更新用户信息,把证书类型修改为“RSA个人单向证书”(默认是“RSA个人双向证书”);


3)、制作证书,在“签发个人证书”时,“证书设备”选择第二个选项(即:MicrosoftEnhanced Cryptographic Provider v1.0)


4)、导出证书:证书制作完成后就可以在IE的Internet选项-内容-证书列表中看到,然后选中该证书,点击导出。导出过程中注意选择“是,导出私钥(Y)”,如图所示:


然后下一步,输入私钥(123456):


最后导出一个.pfx格式的个人证书:


5)、把pfx格式证书转换为JKS格式(pfx格式的证书无法直接引用,需要转换成keystore格式,JKS就是keystore格式之一)。至于如何转换,百度一下,你就知道。

2、    把服务端证书(证书链)导入trust.keystore中备用。

在本案例中,服务端证书(证书链)包括ROOT.cer和CA.cer。这两个证书须导入trust.keystore。用JDK自带的keytool工具实现导入:

keytool-import -alias Root -file d:/Root.cer -keystore "d:/trust.keystore" -storepass123456

keytool-import -alias CA -file d:/CA.cer -keystore "d:/trust.keystore"-storepass 123456

3、    在网关上添加用户,并授予角色。

针对刚刚制作的证书,所关联的用户需在网关上手动录入,并添加到相应的角色中。只有这样,才能通过CA认证网关的系统级权限验证。操作步骤不再赘述。

1.3.2 访问应用子系统

ApacheHttpClient实现携带证书访问SSL服务的基本原理是:首先加载私钥证书到一个KeyStore中,并把服务端可信任证书加载到一个Trusted KeyStore中;然后用这两个KeyStore构造一个SSLContext对象,最终实例化一个CloseableHttpClient对象,并通过CloseableHttpClient去访问SSL服务。

源码:

import java.io.File;

import java.io.FileInputStream;

import java.security.KeyStore;

 

importjavax.net.ssl.SSLContext;

 

import org.apache.http.HttpEntity;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import org.apache.http.conn.ssl.SSLContexts;

import org.apache.http.conn.ssl.TrustSelfSignedStrategy;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClients;

import org.apache.http.util.EntityUtils;

/**

*ThisexampledemonstrateshowtocreatesecureconnectionswithacustomSSLcontext.

*/

public  class MyClientCustomSSL {

 private final static StringTEST_URL ="https://125.35.24.152:446/sfda/HelloWorldServlet";

private final static StringKEYSTORE_FILE ="d:/00000190.jks";

private final static StringTRUSTSTORE_FILE ="d:/trust.keystore";

private final static StringKEYSTORE_PASSWORD ="123456";

 

    public final static void main(String[] args) throws Exception {

    //load the CA CERT(private key):

KeyStore keyStore  =KeyStore.getInstance(KeyStore.getDefaultType());

FileInputStream instream =

new FileInputStream(new File(KEYSTORE_FILE));

try {

        keyStore.load(instream,KEYSTORE_PASSWORD.toCharArray());

} finally {

             instream.close();

}

//load the trusted certs:

KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());

FileInputStream instream1=

new FileInputStream(new File(TRUSTSTORE_FILE));

try {

     trustStore.load(instream1,KEYSTORE_PASSWORD.toCharArray());

} finally {

     instream1.close();

}

// Trust own CA and allself-signed certs

SSLContext sslcontext= SSLContexts.custom()

.loadKeyMaterial(keyStore,KEYSTORE_PASSWORD.toCharArray())

.loadTrustMaterial(trustStore,new TrustSelfSignedStrategy())

.build();

// Allow TLSv1 protocol only

SSLConnectionSocketFactorysslsf =

new SSLConnectionSocketFactory(sslcontext,

                         new String[] {"TLSv1" },

                                null,

SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

         CloseableHttpClient httpclient =HttpClients.custom()

                 .setSSLSocketFactory(sslsf)

                 .build();

try {

HttpGet httpget = new HttpGet(TEST_URL);

System.out.println("ExecutingRequest:" + httpget.getRequestLine());

CloseableHttpResponseresponse = httpclient.execute(httpget);

try {

         HttpEntity entity =response.getEntity();

         System.out.println("-------------------------------------");

System.out.println(response.getStatusLine());

System.out.println(EntityUtils.toString(entity));

         EntityUtils.consume(entity);

     } finally {

response.close();

}

} finally {

 httpclient.close();

}

}

}

1.4 附录

1.4.1 HttpClient4.3官方下载

http://hc.apache.org/httpcomponents-client-4.3.x/download.html

1.4.2 官方示例ClientCustomSSL下载

http://hc.apache.org/httpcomponents-client-4.3.x/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要使用Java实现读取证书访问HTTPS接口,需要遵循以下步骤: 1. 获取证书:首先,需要获取要访问的HTTPS服务器的证书。可以使用浏览器访问服务器,并导出证书为一个文件(一般为.crt或.pem格式)。 2. 将证书导入Java密钥库:将第一步获得的证书导入Java密钥库中。可以使用Java提供的keytool工具,执行类似以下命令: ``` keytool -import -file /path/to/certificate.crt -alias servercert -keystore /path/to/keystore.jks ``` 这将把证书导入到指定的密钥库中,并为证书指定一个别名。 3. 创建SSLContext:使用Java的KeyStore类加载密钥库,并创建一个包含需要的信任管理器的SSLContext实例。可以使用以下代码实现: ```java KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); FileInputStream trustStoreFile = new FileInputStream("/path/to/keystore.jks"); trustStore.load(trustStoreFile, "keystorepassword".toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagerFactory.getTrustManagers(), null); ``` 4. 创建HttpClient:使用Apache HttpClient库创建一个HttpClient对象,并指定使用刚才创建的SSLContext实例来进行HTTPS连接。可以使用以下代码实现: ```java HttpClient client = HttpClients.custom().setSSLContext(sslContext).build(); ``` 5. 发送HTTPS请求:使用HttpClient对象发送HTTPS请求到目标接口。可以使用HttpGet或HttpPost等请求类型,并执行execute方法,如下所示: ```java HttpGet request = new HttpGet("https://api.example.com"); HttpResponse response = client.execute(request); ``` 以上步骤完成后,即可通过Java程序读取证书访问HTTPS接口。需要注意的是,从第3步开始的代码需要进行异常处理,同时确保路径和密码等参数正确配置。 ### 回答2: 要用Java实现读取证书访问HTTPS接口,可以按照以下步骤进行操作: 1. 确保你已经获取到了HTTPS接口所需的证书文件,一般为以.crt、.pem或.jks为扩展名的文件。 2. 首先,需要创建一个HttpClient对象,用于发送HTTP请求。可以使用Apache HttpClient库来实现,该库提供了丰富的HTTP客户端功能。 3. 创建SSLContext对象,用于在发送HTTPS请求时验证服务证书的有效性。可以使用KeyStore类加载证书文件,并通过TrustManagerFactory初始化SSLContext。 4. 创建一个HostnameVerifier对象,用于验证服务器主机名的有效性。可以使用自定义的实现类,也可以使用默认的实现类。 5. 创建一个HttpClientBuilder对象,并将SSLContext和HostnameVerifier对象设置给它。 6. 使用HttpClientBuilder对象创建HttpClient对象,同时设置代理、超时等相关参数。 7. 创建一个HttpGet或HttpPost对象,设置请求的URL和相关参数。 8. 调用HttpClient对象的execute方法发送请求,并获取返回的HttpResponse对象。 9. 从HttpResponse对象中获取服务器返回的数据,并进行后续处理。 示例代码如下: ```java import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.security.KeyStore; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustManagerFactoryBuilder; public class HttpsClientExample { public static void main(String[] args) { try { // 加载证书 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(HttpsClientExample.class.getResourceAsStream("client-truststore.crt"), "password".toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactoryBuilder.newBuilder() .withDefaultAlgorithm() .withKeystore(trustStore) .build(); SSLContext sslContext = SSLContextBuilder.create() .loadTrustMaterial(trustManagerFactory) .build(); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext)) .build(); HttpGet httpGet = new HttpGet("https://example.com/api"); HttpResponse response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); // 读取返回的数据 InputStream inputStream = entity.getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } httpClient.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 以上就是使用Java实现读取证书访问HTTPS接口的基本步骤,根据具体的证书和接口要求,可能需要进行一些额外的配置和参数设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值