如何使用现有证书连接到服务器以在 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

等实用程序将证书添加到商店中