如何在客户端 java 应用程序中使用客户端证书?
How do I use client certificates in a client java application?
这个话题我花了很长时间才弄明白。零散的信息零散,必须将所有内容放在一起。我希望通过这个 post 我可以帮助其他人快速 assemble 一个可行的解决方案。
我有一个 client-cert.pem
、client-key.pem
和一个 root.pem
文件,我需要在我的 Java 客户端中使用它们来访问远程 REST API.
如何将它们打包到信任库中并使用它们进行 API 调用?
为了将您的证书加载到您的应用程序中,您需要将它们打包到信任库中。
创建信任库
给定 3 个文件:
client-cert.pem
client-key.pem
root.pem
运行 在您的终端中执行以下命令。将 PASSWORD
替换为您想要的密码。
将您的客户端密钥和证书打包到密钥库中。这将创建一个 PKCS12 密钥库文件。
openssl pkcs12 -export \
-inkey client-key.pem -in client-cert.pem \
-out client.pfx -passout pass:PASSWORD \
-name qlikClient
将密钥库添加到您的信任库。如果目的地不存在,它将创建一个信任库。这将创建一个 PKCS12
信任库文件。默认情况下,它会创建一个专有格式的 JKS
文件。通过指定 -deststoretype PKCS12
,您将创建一个行业标准格式的文件。
keytool -importkeystore \
-destkeystore truststore.pfx -deststoretype PKCS12 -deststorepass PASSWORD \
-srckeystore client.pfx -srcstorepass PASSWORD -srcstoretype PKCS12 \
-alias qlikClient
将您的根 CA 添加到信任库
keytool -importcert \
-keystore truststore.pfx -storepass PASSWORD \
-file root.pem -noprompt \
-alias qlikServerCACert
请注意,在上面的命令中,我们对密钥库和信任库使用相同的 PASSWORD
。您也可以使用不同的密码。另请注意,您必须为添加到信任库的每个项目指定一个别名。
如果您希望信任库信任系统中所有可用的 cacer,请将 -trustcacerts
选项添加到步骤 2 或 3。
您可以使用以下命令列出信任库的内容
keytool -list -keystore truststore.pfx -storepass PASSWORD
在您的应用程序中使用信任库
拥有信任库后,您需要将其加载到您的应用程序中。假设您有一个常量 KEYSTORE_PATH
保存您的信任库的路径并且 keyStorePass
保存密码,将信任库文件读入 KeyStore
private KeyStore readStore() {
try (InputStream keyStoreStream = new FileInputStream(KEYSTORE_PATH)) {
KeyStore keyStore = KeyStore.getInstance("PKCS12"); // or "JKS"
keyStore.load(keyStoreStream, keyStorePass.toCharArray());
return keyStore;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
创建自定义 SSLContext
和自定义 HttpClient
,
final KeyStore truststore = readStore();
final SSLContext sslContext;
try {
sslContext = SSLContexts.custom()
.loadTrustMaterial(truststore, new TrustAllStrategy())
.loadKeyMaterial(truststore, keyStorePass.toCharArray(), (aliases, socket) -> "qlikClient")
.build();
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) {
throw new RuntimeException("Failed to read keystore", e);
}
final CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
您现在可以使用此 HttpClient
向您的 API 发出请求。
HttpResponse response = httpClient.execute(new HttpGet("https://sense-gcp-central1eu.net:4242/qrs/app/full"));
或者,如果您使用的是 OpenUnirest/unirest-java 库,您可以配置 Unirest 以使用您的自定义 HttpClient
Unirest.config().httpClient(httpClient);
HttpResponse<JsonNode> response = Unirest.get("https://sense-gcp-central1eu.net:4242/qrs/app/full").asJson();
参考资料
这个话题我花了很长时间才弄明白。零散的信息零散,必须将所有内容放在一起。我希望通过这个 post 我可以帮助其他人快速 assemble 一个可行的解决方案。
我有一个 client-cert.pem
、client-key.pem
和一个 root.pem
文件,我需要在我的 Java 客户端中使用它们来访问远程 REST API.
如何将它们打包到信任库中并使用它们进行 API 调用?
为了将您的证书加载到您的应用程序中,您需要将它们打包到信任库中。
创建信任库
给定 3 个文件:
client-cert.pem
client-key.pem
root.pem
运行 在您的终端中执行以下命令。将 PASSWORD
替换为您想要的密码。
将您的客户端密钥和证书打包到密钥库中。这将创建一个 PKCS12 密钥库文件。
openssl pkcs12 -export \ -inkey client-key.pem -in client-cert.pem \ -out client.pfx -passout pass:PASSWORD \ -name qlikClient
将密钥库添加到您的信任库。如果目的地不存在,它将创建一个信任库。这将创建一个
PKCS12
信任库文件。默认情况下,它会创建一个专有格式的JKS
文件。通过指定-deststoretype PKCS12
,您将创建一个行业标准格式的文件。keytool -importkeystore \ -destkeystore truststore.pfx -deststoretype PKCS12 -deststorepass PASSWORD \ -srckeystore client.pfx -srcstorepass PASSWORD -srcstoretype PKCS12 \ -alias qlikClient
将您的根 CA 添加到信任库
keytool -importcert \ -keystore truststore.pfx -storepass PASSWORD \ -file root.pem -noprompt \ -alias qlikServerCACert
请注意,在上面的命令中,我们对密钥库和信任库使用相同的 PASSWORD
。您也可以使用不同的密码。另请注意,您必须为添加到信任库的每个项目指定一个别名。
如果您希望信任库信任系统中所有可用的 cacer,请将 -trustcacerts
选项添加到步骤 2 或 3。
您可以使用以下命令列出信任库的内容
keytool -list -keystore truststore.pfx -storepass PASSWORD
在您的应用程序中使用信任库
拥有信任库后,您需要将其加载到您的应用程序中。假设您有一个常量 KEYSTORE_PATH
保存您的信任库的路径并且 keyStorePass
保存密码,将信任库文件读入 KeyStore
private KeyStore readStore() {
try (InputStream keyStoreStream = new FileInputStream(KEYSTORE_PATH)) {
KeyStore keyStore = KeyStore.getInstance("PKCS12"); // or "JKS"
keyStore.load(keyStoreStream, keyStorePass.toCharArray());
return keyStore;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
创建自定义 SSLContext
和自定义 HttpClient
,
final KeyStore truststore = readStore();
final SSLContext sslContext;
try {
sslContext = SSLContexts.custom()
.loadTrustMaterial(truststore, new TrustAllStrategy())
.loadKeyMaterial(truststore, keyStorePass.toCharArray(), (aliases, socket) -> "qlikClient")
.build();
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) {
throw new RuntimeException("Failed to read keystore", e);
}
final CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
您现在可以使用此 HttpClient
向您的 API 发出请求。
HttpResponse response = httpClient.execute(new HttpGet("https://sense-gcp-central1eu.net:4242/qrs/app/full"));
或者,如果您使用的是 OpenUnirest/unirest-java 库,您可以配置 Unirest 以使用您的自定义 HttpClient
Unirest.config().httpClient(httpClient);
HttpResponse<JsonNode> response = Unirest.get("https://sense-gcp-central1eu.net:4242/qrs/app/full").asJson();
参考资料