如何使用现有证书连接到服务器以在 Java 中通过 HTTPS 获得 JSON 响应?
How do I use an existing certificate to connect to a server to get a JSON response with HTTPS in Java?
我正在尝试从带有 GET 请求的 API 调用中获取 JSON 响应。我知道服务器受到保护,应用程序需要证书才能拨打电话。
现在我有一个 certificate.pfx
文件,我可以将其导入浏览器并从服务器获取响应。
如何使用我的 Java 应用程序执行此操作,以便应用程序使用证书连接到服务器并获取响应?
package controllers;
import com.fasterxml.jackson.databind.JsonNode;
import models.UserProfile;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import saleem.orm.utils.HibernateUtil;
import javax.net.ssl.HttpsURLConnection;
import javax.persistence.EntityManager;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class HomeController extends Controller {
public Result login() {
RequestJSON();
return ok(views.html.login.render());
}
public Result register() {
return ok(views.html.register.render());
}
public Result start() {
return ok(views.html.start.render());
}
public void RequestJSON() {
try {
// Censored the URL for the question
URL url = new URL("https://");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type", "application/json");
con.connect();
String res = con.getResponseMessage();
con.disconnect();
System.out.println(res);
} catch (IOException e) {
e.printStackTrace();
}
}
我的应用程序尝试连接到服务器时的堆栈跟踪:
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 sun.security.ssl.Alerts.getSSLException(Alerts.java:198)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1967)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:331)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:325)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1689)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:226)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1082)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:1010)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1079)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1388)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1416)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1400)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:167)
at controllers.HomeController.RequestJSON(HomeController.java:56)
at controllers.HomeController.login(HomeController.java:24)
at router.Routes$$anonfun$routes.$anonfun$applyOrElse(Routes.scala:193)
at play.core.routing.HandlerInvokerFactory$$anon.resultCall(HandlerInvoker.scala:142)
at play.core.routing.HandlerInvokerFactory$$anon.resultCall(HandlerInvoker.scala:141)
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$$anon$$anon.invocation(HandlerInvoker.scala:115)
at play.core.j.JavaAction$$anon.call(JavaAction.scala:119)
at play.http.DefaultActionCreator.call(DefaultActionCreator.java:33)
at play.core.j.JavaAction.$anonfun$apply(JavaAction.scala:175)
at scala.concurrent.Future$.$anonfun$apply(Future.scala:672)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:431)
at play.core.j.HttpExecutionContext.$anonfun$execute(HttpExecutionContext.scala:64)
at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:59)
at scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:393)
at scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:302)
at scala.concurrent.impl.Promise$DefaultPromise.dispatchOrAddCallbacks(Promise.scala:276)
at scala.concurrent.impl.Promise$DefaultPromise.map(Promise.scala:146)
at scala.concurrent.Future$.apply(Future.scala:672)
at play.core.j.JavaAction.apply(JavaAction.scala:176)
at play.api.mvc.Action.$anonfun$apply(Action.scala:82)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture(Accumulator.scala:168)
at scala.util.Try$.apply(Try.scala:210)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture(Accumulator.scala:168)
at scala.Function1.$anonfun$andThen(Function1.scala:85)
at scala.Function1.$anonfun$andThen(Function1.scala:85)
at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:199)
at play.core.server.AkkaHttpServer.$anonfun$runAction(AkkaHttpServer.scala:417)
at akka.http.scaladsl.util.FastFuture$.strictTransform(FastFuture.scala:41)
at akka.http.scaladsl.util.FastFuture$.$anonfun$transformWith(FastFuture.scala:51)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:448)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:48)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:48)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:450)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:317)
at sun.security.validator.Validator.validate(Validator.java:262)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:227)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1671)
... 47 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:445)
... 53 more
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
根据上述异常,客户端未验证服务器身份。客户端必须在 SSL handshake
过程中验证传入的服务器证书,并且该客户端依赖 java 信任库中存在的根证书(用于签署服务器证书的证书)。此外,这取决于客户端在建立连接时要使用哪个信任库。
以下用于为默认 java 信任库添加证书,即 cacerts
。
在您的系统上找到 java 信任库。通常,在windowsos,可以在JAVA_HOME/jre/lib/security/cacerts
找到。您可以使用默认密码 changeit
访问此信任库。使用 keytool
等实用程序将证书添加到商店中
我正在尝试从带有 GET 请求的 API 调用中获取 JSON 响应。我知道服务器受到保护,应用程序需要证书才能拨打电话。
现在我有一个 certificate.pfx
文件,我可以将其导入浏览器并从服务器获取响应。
如何使用我的 Java 应用程序执行此操作,以便应用程序使用证书连接到服务器并获取响应?
package controllers;
import com.fasterxml.jackson.databind.JsonNode;
import models.UserProfile;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import saleem.orm.utils.HibernateUtil;
import javax.net.ssl.HttpsURLConnection;
import javax.persistence.EntityManager;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class HomeController extends Controller {
public Result login() {
RequestJSON();
return ok(views.html.login.render());
}
public Result register() {
return ok(views.html.register.render());
}
public Result start() {
return ok(views.html.start.render());
}
public void RequestJSON() {
try {
// Censored the URL for the question
URL url = new URL("https://");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type", "application/json");
con.connect();
String res = con.getResponseMessage();
con.disconnect();
System.out.println(res);
} catch (IOException e) {
e.printStackTrace();
}
}
我的应用程序尝试连接到服务器时的堆栈跟踪:
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 sun.security.ssl.Alerts.getSSLException(Alerts.java:198)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1967)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:331)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:325)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1689)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:226)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1082)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:1010)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1079)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1388)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1416)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1400)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:167)
at controllers.HomeController.RequestJSON(HomeController.java:56)
at controllers.HomeController.login(HomeController.java:24)
at router.Routes$$anonfun$routes.$anonfun$applyOrElse(Routes.scala:193)
at play.core.routing.HandlerInvokerFactory$$anon.resultCall(HandlerInvoker.scala:142)
at play.core.routing.HandlerInvokerFactory$$anon.resultCall(HandlerInvoker.scala:141)
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$$anon$$anon.invocation(HandlerInvoker.scala:115)
at play.core.j.JavaAction$$anon.call(JavaAction.scala:119)
at play.http.DefaultActionCreator.call(DefaultActionCreator.java:33)
at play.core.j.JavaAction.$anonfun$apply(JavaAction.scala:175)
at scala.concurrent.Future$.$anonfun$apply(Future.scala:672)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:431)
at play.core.j.HttpExecutionContext.$anonfun$execute(HttpExecutionContext.scala:64)
at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:59)
at scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:393)
at scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:302)
at scala.concurrent.impl.Promise$DefaultPromise.dispatchOrAddCallbacks(Promise.scala:276)
at scala.concurrent.impl.Promise$DefaultPromise.map(Promise.scala:146)
at scala.concurrent.Future$.apply(Future.scala:672)
at play.core.j.JavaAction.apply(JavaAction.scala:176)
at play.api.mvc.Action.$anonfun$apply(Action.scala:82)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture(Accumulator.scala:168)
at scala.util.Try$.apply(Try.scala:210)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture(Accumulator.scala:168)
at scala.Function1.$anonfun$andThen(Function1.scala:85)
at scala.Function1.$anonfun$andThen(Function1.scala:85)
at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:199)
at play.core.server.AkkaHttpServer.$anonfun$runAction(AkkaHttpServer.scala:417)
at akka.http.scaladsl.util.FastFuture$.strictTransform(FastFuture.scala:41)
at akka.http.scaladsl.util.FastFuture$.$anonfun$transformWith(FastFuture.scala:51)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:448)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:48)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:48)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:450)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:317)
at sun.security.validator.Validator.validate(Validator.java:262)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:227)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1671)
... 47 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:445)
... 53 more
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
根据上述异常,客户端未验证服务器身份。客户端必须在 SSL handshake
过程中验证传入的服务器证书,并且该客户端依赖 java 信任库中存在的根证书(用于签署服务器证书的证书)。此外,这取决于客户端在建立连接时要使用哪个信任库。
以下用于为默认 java 信任库添加证书,即 cacerts
。
在您的系统上找到 java 信任库。通常,在windowsos,可以在JAVA_HOME/jre/lib/security/cacerts
找到。您可以使用默认密码 changeit
访问此信任库。使用 keytool