使用带有标头的REST客户端时获取ssl.SSLHandshakeException但与PostMan一起正常工作

我有一个外部REST资源,其中包含以下细节:

  1. url: abc.com/orders (域名为https
  2. 我需要将UserID作为HTTP标头传递,密钥“user”值为“abcd”
  3. 这将返回JSON响应

我正在使用Java代码以下:

 try { Client client = Client.create(); WebResource webResource = client.resource("abc.com/orders"); ClientResponse response = webResource.header("user", "abcd").accept("application/json") .get(ClientResponse.class); if (response.getStatus() != 200) { throw new RuntimeException("Failed : HTTP error code : " + response.getStatus()); } String output = response.getEntity(String.class); System.out.println("Output from Server .... \n"); System.out.println(output); } catch (Exception e) { e.printStackTrace(); } 

但我得到的是exception,尽管它与PostMan工作正常

 com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:155) at com.sun.jersey.api.client.Client.handle(Client.java:652) at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:509) 

我尝试在它上面搜索一下,发现我需要从该URL获取证书并添加到jdk/lib/security文件夹。 但我不知道该怎么办。

使用openssl我得到以下输出:

 user>openssl s_client -connect abc.com:443 CONNECTED(00000214) 7832:error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error:s23_clnt.c:802: --- no peer certificate available --- No client certificate CA names sent --- SSL handshake has read 7 bytes and written 308 bytes --- New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : 0000 Session-ID: Session-ID-ctx: Master-Key: Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None Start Time: 1531657560 Timeout : 300 (sec) Verify return code: 0 (ok) 

这些是使您的程序工作的说明。 顺便说一句,我在Windows上,使用谷歌浏览器。

你需要一个证书。

1)首先,转到url(如果它是一个网站或一个宁静的服务无关紧要),让我们选择google.com。 右键单击页面,然后单击“检查”。

在此处输入图像描述

2)转到安全选项卡。

在此处输入图像描述

3)一旦,你在那里,点击“查看证书”。 在此处输入图像描述

将弹出一个窗口,其中包含站点证书的详细信息。

4)转到“认证路径”选项卡。 并从层次结构中双击所需的证书。 在此处输入图像描述

将弹出一个新窗口:

在此处输入图像描述

在这种情况下,我选择了名为“Google信任服务…”的根证书,但您可以选择更具体的证书,例如“Google Internet Authority G3”。 我认为它越具体,它提供的安全性就越高(但我不确定)。

5)转到“详细信息”选项卡,然后选择证书的名称:

在此处输入图像描述

6)单击“复制到文件”,然后选择其名称以及要保存的位置。 我把它保存在桌面上并命名为“test.cer”。

现在您已完成导出证书。 接下来,您要将其添加到jvm的truststore。

1)查找运行应用程序的JRE,例如我的计算机上只有一个JRE(不包括与JDK捆绑的JRE)。 它位于这里:

在此处输入图像描述

存储证书的目标文件是cacerts:

在此处输入图像描述

2)以管理员身份打开cmd并执行cd "C:\Program Files\Java\jre-10.0.1\lib\security" (在我的情况下为cacerts的路径)。

3)发出以下命令:

keytool -import -storepass changeit -noprompt -alias *alias* -keystore cacerts -trustcacerts -file *path_to_certificate*

请注意,别名可以是任何内容,无论您将文件称为什么,只要它不与信任库中已有的其他证书的别名冲突即可。

在我的情况下,我发出这个:

在此处输入图像描述

4)您现在可以发出以下命令: keytool -list -keystore cacerts -alias *alias*以确保添加了证书。 发出此命令时,它会询问您的密码。 在第三步中,我给你的命令有这个选项: -storepass changeit ,所以你的密码将会改变。

在此处输入图像描述

在我的情况下一切都很好。

5)现在您可以重新启动应用程序,它应该可以工作。 有些人建议重新启动计算机,但我不知道是否有必要。