java - 无法使用 Apache HttpClient/OkHttp 在 POST 请求中发送 .p12 文件
问题描述
我正在尝试使用 java 执行相互身份验证。我已经尝试过curl
,它正在使用以下命令:
curl --cert-type P12 --cert my-p12-file.p12:password https://server-url --header "Content-Type:application/json" --data '{"key":"value"}'
或者
curl --cert client.crt --key my-key.pem --cacert RootCA.cer https://server-url --header "Content-Type:application/json" --data '{"key":"value"}'
这两个命令都工作正常并给出正确的输出。我在 Postman 中尝试过相同的功能,它也在那里工作。当我以编程方式尝试它时,它在 nodejs 中工作,但不在 Java 中。我关注了许多博客/教程/SO答案,但没有任何效果。这是Java代码:
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.File;
public class DemoSO {
private static CloseableHttpClient httpClient;
public static void main(String[] args) throws Exception {
System.setProperty("javax.net.debug", "ssl");
String trustStore = "root-certificate-truststore.jks";
String keyStore = "keystore-v0.jks";
String extraPwd = "password";
SSLContext sslContext = SSLContexts.custom().
loadKeyMaterial(new File(keyStore),extraPwd.toCharArray(),extraPwd.toCharArray())
.loadTrustMaterial(new File(trustStore))
.build();
SSLConnectionSocketFactory sslConSocFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
httpClient = HttpClients.custom().setSSLSocketFactory(sslConSocFactory)
.setSSLContext(sslContext)
.build();
HttpPost httpPost = new HttpPost("https://server-url");
String requestBody = "{\"key\":\"value\"}";
StringEntity entity = new StringEntity(requestBody);
Header header = new BasicHeader("Content-Type", "application/json");
entity.setContentType(header);
httpPost.setHeader(header);
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
for (Header allHeader : response.getAllHeaders()) {
System.out.println(allHeader.toString());
}
System.out.println(response.getAllHeaders().toString());
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
}
}
上面的代码发送一个 POST 请求到https://server-url
. trustStore 是使用以下命令从根证书生成的:
openssl x509 -inform der -in RootCA.cer -outform pem -out root-certificate.pem
(转换.cer
为.pem
)
keytool -import -file root-certificate.pem -alias root-certificate -keystore root-certificate-truststore.jks
keyStore 是使用 .p12 文件生成的,该文件通过 openssl、postman 和 node 程序运行良好。
keytool -importkeystore -srckeystore my-p12-file.p12 -destkeystore keystore-v0.jks -srcstoretype PKCS12 -deststoretype jks -deststorepass password
任何在 java 中实现的帮助或建议将不胜感激。
谢谢。
[编辑1]
忘记添加回复了。它给出了 401 Unauthorized。这与之前在 cURL 和 postman 中给出的错误相同,但是当我传递 .p12 文件时,它开始正常工作并在响应代码中给出 200。
<ErrorCode>401-Unauthorized</ErrorCode>
<ErrorMessageCode>3103</ErrorMessageCode>
<ErrorMessage>Not enough authentication factor, 1 is required!</ErrorMessage>
调试模式显示以下错误:
upcoming handshake states: client finished[20]
upcoming handshake states: server change_cipher_spec[-1]
upcoming handshake states: server finished[20]
*** ServerHelloDone
[read] MD5 and SHA1 hashes: len = 4
0000: 0E 00 00 00 ....
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
***
update handshake state: certificate[11]
upcoming handshake states: client_key_exc
解决方案
推荐阅读
- r - 在数据框中添加条件变量,该变量考虑同一数据框的行之间的时间间隔
- angular - 如何使用 rxjs 运算符和转换链接多个依赖订阅?
- android - 添加指示重复类的新依赖项后项目构建失败
- javascript - 我的功能总是会告诉我我的问题错了。为什么?
- html - 如何让响应式设计顺利融入移动设计?
- react-native - React 本机发布版本无法连接到互联网
- c++ - 我们可以在整数类型的双指针中分配二维整数数组的地址吗?怎么可能?
- javascript - JavaScript 闭包行为异常
- mysql - 如何根据 MySQL 中所有三个中的字段从另外两个中更新一个表
- angular - 从自定义角度管道中的承诺返回项目