简单的 Java HTTPS 服务器

发布于 2024-08-22 19:43:36 字数 520 浏览 6 评论 0 原文

我需要为 Java 应用程序设置一个真正轻量级的 HTTPS 服务器。它是我们的开发实验室中使用的一个模拟器,用于模拟一台设备在野外接受的 HTTPS 连接。因为它纯粹是一个轻量级开发工具,根本不以任何方式用于生产,所以我很高兴能够绕过认证和尽可能多的谈判。

我计划在 Java 6 SE 中使用 HttpsServer 类,但我很难让它正常工作。作为测试客户端,我在 cygwin 命令行 (wget https://[address]:[port]) 中使用 wget,但是 wget code> 报告“无法建立 SSL 连接”。

如果我使用 -d 选项运行 wget 进行调试,它会告诉我“SSL 握手失败”。

我花了 30 分钟在谷歌上搜索这个内容,一切似乎都指向了相当无用的 Java 6 文档,该文档描述了这些方法,但实际上并没有讨论如何让该死的东西说话,也根本没有提供任何示例代码。

有人能把我推向正确的方向吗?

I need to set up a really lightweight HTTPS server for a Java application. It's a simulator that's being used in our development labs to simulate the HTTPS connections accepted by a piece of equipment in the wild. Because it's purely a lightweight development tool and isn't used in production in any way at all, I'm quite happy to bypass certifications and as much negotiation as I can.

I'm planning on using the HttpsServer class in Java 6 SE but I'm struggling to get it working. As a test client, I'm using wget from the cygwin command line (wget https://[address]:[port]) but wget reports that it was "Unable to establish SSL connection".

If I run wget with the -d option for debugging it tells me "SSL handshake failed".

I've spent 30 minutes googling this and everything seems to just point back to the fairly useless Java 6 documentation that describes the methods but doesn't actually talk about how to get the darn thing talking or provide any example code at all.

Can anyone nudge me in the right direction?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心房敞 2024-08-29 19:43:36

我最终使用的是:

try {
    // Set up the socket address
    InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), config.getHttpsPort());

    // Initialise the HTTPS server
    HttpsServer httpsServer = HttpsServer.create(address, 0);
    SSLContext sslContext = SSLContext.getInstance("TLS");

    // Initialise the keystore
    char[] password = "simulator".toCharArray();
    KeyStore ks = KeyStore.getInstance("JKS");
    FileInputStream fis = new FileInputStream("lig.keystore");
    ks.load(fis, password);

    // Set up the key manager factory
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, password);

    // Set up the trust manager factory
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    tmf.init(ks);

    // Set up the HTTPS context and parameters
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
        public void configure(HttpsParameters params) {
            try {
                // Initialise the SSL context
                SSLContext c = SSLContext.getDefault();
                SSLEngine engine = c.createSSLEngine();
                params.setNeedClientAuth(false);
                params.setCipherSuites(engine.getEnabledCipherSuites());
                params.setProtocols(engine.getEnabledProtocols());

                // Get the default parameters
                SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
                params.setSSLParameters(defaultSSLParameters);
            } catch (Exception ex) {
                ILogger log = new LoggerFactory().getLogger();
                log.exception(ex);
                log.error("Failed to create HTTPS port");
            }
        }
    });
    LigServer server = new LigServer(httpsServer);
    joinableThreadList.add(server.getJoinableThread());
} catch (Exception exception) {
    log.exception(exception);
    log.error("Failed to create HTTPS server on port " + config.getHttpsPort() + " of localhost");
}

要生成密钥库:

$ keytool -genkeypair -keyalg RSA -alias self_signed -keypass simulator \
  -keystore lig.keystore -storepass simulator

另请参阅此处

storepass 和 keypass 可能不同,在这种情况下,ks.loadkmf.init 必须分别使用 storepass 和 keypass。

What I eventually used was this:

try {
    // Set up the socket address
    InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), config.getHttpsPort());

    // Initialise the HTTPS server
    HttpsServer httpsServer = HttpsServer.create(address, 0);
    SSLContext sslContext = SSLContext.getInstance("TLS");

    // Initialise the keystore
    char[] password = "simulator".toCharArray();
    KeyStore ks = KeyStore.getInstance("JKS");
    FileInputStream fis = new FileInputStream("lig.keystore");
    ks.load(fis, password);

    // Set up the key manager factory
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, password);

    // Set up the trust manager factory
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    tmf.init(ks);

    // Set up the HTTPS context and parameters
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
        public void configure(HttpsParameters params) {
            try {
                // Initialise the SSL context
                SSLContext c = SSLContext.getDefault();
                SSLEngine engine = c.createSSLEngine();
                params.setNeedClientAuth(false);
                params.setCipherSuites(engine.getEnabledCipherSuites());
                params.setProtocols(engine.getEnabledProtocols());

                // Get the default parameters
                SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
                params.setSSLParameters(defaultSSLParameters);
            } catch (Exception ex) {
                ILogger log = new LoggerFactory().getLogger();
                log.exception(ex);
                log.error("Failed to create HTTPS port");
            }
        }
    });
    LigServer server = new LigServer(httpsServer);
    joinableThreadList.add(server.getJoinableThread());
} catch (Exception exception) {
    log.exception(exception);
    log.error("Failed to create HTTPS server on port " + config.getHttpsPort() + " of localhost");
}

To generate a keystore:

$ keytool -genkeypair -keyalg RSA -alias self_signed -keypass simulator \
  -keystore lig.keystore -storepass simulator

See also here.

Potentially storepass and keypass might be different, in which case the ks.load and kmf.init must use storepass and keypass, respectively.

岁月无声 2024-08-29 19:43:36

我更新了您对 HTTPS 服务器(不是基于套接字)的答案。它可能有助于 CSRF 和 AJAX 调用。

import java.io.*;
import java.net.InetSocketAddress;
import java.lang.*;
import java.net.URL;
import com.sun.net.httpserver.HttpsServer;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.*;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;

import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URLConnection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

import java.net.InetAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsExchange;

public class SimpleHTTPSServer {

    public static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            HttpsExchange httpsExchange = (HttpsExchange) t;
            t.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
            t.sendResponseHeaders(200, response.getBytes().length);
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {

        try {
            // setup the socket address
            InetSocketAddress address = new InetSocketAddress(8000);

            // initialise the HTTPS server
            HttpsServer httpsServer = HttpsServer.create(address, 0);
            SSLContext sslContext = SSLContext.getInstance("TLS");

            // initialise the keystore
            char[] password = "password".toCharArray();
            KeyStore ks = KeyStore.getInstance("JKS");
            FileInputStream fis = new FileInputStream("testkey.jks");
            ks.load(fis, password);

            // setup the key manager factory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password);

            // setup the trust manager factory
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);

            // setup the HTTPS context and parameters
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
                public void configure(HttpsParameters params) {
                    try {
                        // initialise the SSL context
                        SSLContext context = getSSLContext();
                        SSLEngine engine = context.createSSLEngine();
                        params.setNeedClientAuth(false);
                        params.setCipherSuites(engine.getEnabledCipherSuites());
                        params.setProtocols(engine.getEnabledProtocols());

                        // Set the SSL parameters
                        SSLParameters sslParameters = context.getSupportedSSLParameters();
                        params.setSSLParameters(sslParameters);

                    } catch (Exception ex) {
                        System.out.println("Failed to create HTTPS port");
                    }
                }
            });
            httpsServer.createContext("/test", new MyHandler());
            httpsServer.setExecutor(null); // creates a default executor
            httpsServer.start();

        } catch (Exception exception) {
            System.out.println("Failed to create HTTPS server on port " + 8000 + " of localhost");
            exception.printStackTrace();

        }
    }

}

要创建自签名证书:

keytool -genkeypair -keyalg RSA -alias selfsigned -keystore testkey.jks -storepass password -validity 360 -keysize 2048

I updated your answer for a HTTPS server (not socket-based). It might help with CSRF and AJAX calls.

import java.io.*;
import java.net.InetSocketAddress;
import java.lang.*;
import java.net.URL;
import com.sun.net.httpserver.HttpsServer;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.*;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;

import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URLConnection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

import java.net.InetAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsExchange;

public class SimpleHTTPSServer {

    public static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            HttpsExchange httpsExchange = (HttpsExchange) t;
            t.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
            t.sendResponseHeaders(200, response.getBytes().length);
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {

        try {
            // setup the socket address
            InetSocketAddress address = new InetSocketAddress(8000);

            // initialise the HTTPS server
            HttpsServer httpsServer = HttpsServer.create(address, 0);
            SSLContext sslContext = SSLContext.getInstance("TLS");

            // initialise the keystore
            char[] password = "password".toCharArray();
            KeyStore ks = KeyStore.getInstance("JKS");
            FileInputStream fis = new FileInputStream("testkey.jks");
            ks.load(fis, password);

            // setup the key manager factory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password);

            // setup the trust manager factory
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);

            // setup the HTTPS context and parameters
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
                public void configure(HttpsParameters params) {
                    try {
                        // initialise the SSL context
                        SSLContext context = getSSLContext();
                        SSLEngine engine = context.createSSLEngine();
                        params.setNeedClientAuth(false);
                        params.setCipherSuites(engine.getEnabledCipherSuites());
                        params.setProtocols(engine.getEnabledProtocols());

                        // Set the SSL parameters
                        SSLParameters sslParameters = context.getSupportedSSLParameters();
                        params.setSSLParameters(sslParameters);

                    } catch (Exception ex) {
                        System.out.println("Failed to create HTTPS port");
                    }
                }
            });
            httpsServer.createContext("/test", new MyHandler());
            httpsServer.setExecutor(null); // creates a default executor
            httpsServer.start();

        } catch (Exception exception) {
            System.out.println("Failed to create HTTPS server on port " + 8000 + " of localhost");
            exception.printStackTrace();

        }
    }

}

To create a self-signed certificate:

keytool -genkeypair -keyalg RSA -alias selfsigned -keystore testkey.jks -storepass password -validity 360 -keysize 2048
寂寞陪衬 2024-08-29 19:43:36

使用 ServerSocket

您可以使用 HttpsServer 的构建更加轻量级:ServerSocket

单线程

以下程序是一个非常简单的单线程服务器,侦听端口 8443。消息使用 ./keystore.jks 中的密钥通过 TLS 进行加密:

public static void main(String... args) {
var address = new InetSocketAddress("0.0.0.0", 8443);

startSingleThreaded(address);
}

public static void startSingleThreaded(InetSocketAddress address) {

System.out.println("Start single-threaded server at " + address);

try (var serverSocket = getServerSocket(address)) {

var encoding = StandardCharsets.UTF_8;

// This infinite loop is not CPU-intensive since method "accept" blocks
// until a client has made a connection to the socket
while (true) {
try (var socket = serverSocket.accept();
// Use the socket to read the client's request
var reader = new BufferedReader(new InputStreamReader(
socket.getInputStream(), encoding.name()));
// Writing to the output stream and then closing it sends
// data to the client
var writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream(), encoding.name()))
) {
getHeaderLines(reader).forEach(System.out::println);

writer.write(getResponse(encoding));
writer.flush();

} catch (IOException e) {
System.err.println("Exception while handling connection");
e.printStackTrace();
}
}
} catch (Exception e) {
System.err.println("Could not create socket at " + address);
e.printStackTrace();
}
}

private static ServerSocket getServerSocket(InetSocketAddress address)
throws Exception {

// Backlog is the maximum number of pending connections on the socket,
// 0 means that an implementation-specific default is used
int backlog = 0;

var keyStorePath = Path.of("./keystore.jks");
char[] keyStorePassword = "pass_for_self_signed_cert".toCharArray();

// Bind the socket to the given port and address
var serverSocket = getSslContext(keyStorePath, keyStorePassword)
.getServerSocketFactory()
.createServerSocket(address.getPort(), backlog, address.getAddress());

// We don't need the password anymore → Overwrite it
Arrays.fill(keyStorePassword, '0');

return serverSocket;
}

private static SSLContext getSslContext(Path keyStorePath, char[] keyStorePass)
throws Exception {

var keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(keyStorePath.toFile()), keyStorePass);

var keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, keyStorePass);

var sslContext = SSLContext.getInstance("TLS");
// Null means using default implementations for TrustManager and SecureRandom
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
return sslContext;
}

private static String getResponse(Charset encoding) {
var body = "The server says hi

With ServerSocket

You can use the class that HttpsServer is built around to be even more light-weight: ServerSocket.

Single-threaded

The following program is a very simple, single-threaded server listening on port 8443. Messages are encrypted with TLS using the keys in ./keystore.jks:

public static void main(String... args) {
    var address = new InetSocketAddress("0.0.0.0", 8443);

    startSingleThreaded(address);
}

public static void startSingleThreaded(InetSocketAddress address) {

    System.out.println("Start single-threaded server at " + address);

    try (var serverSocket = getServerSocket(address)) {

        var encoding = StandardCharsets.UTF_8;

        // This infinite loop is not CPU-intensive since method "accept" blocks
        // until a client has made a connection to the socket
        while (true) {
            try (var socket = serverSocket.accept();
                 // Use the socket to read the client's request
                 var reader = new BufferedReader(new InputStreamReader(
                         socket.getInputStream(), encoding.name()));
                 // Writing to the output stream and then closing it sends
                 // data to the client
                 var writer = new BufferedWriter(new OutputStreamWriter(
                         socket.getOutputStream(), encoding.name()))
            ) {
                getHeaderLines(reader).forEach(System.out::println);

                writer.write(getResponse(encoding));
                writer.flush();

            } catch (IOException e) {
                System.err.println("Exception while handling connection");
                e.printStackTrace();
            }
        }
    } catch (Exception e) {
        System.err.println("Could not create socket at " + address);
        e.printStackTrace();
    }
}

private static ServerSocket getServerSocket(InetSocketAddress address)
        throws Exception {

    // Backlog is the maximum number of pending connections on the socket,
    // 0 means that an implementation-specific default is used
    int backlog = 0;

    var keyStorePath = Path.of("./keystore.jks");
    char[] keyStorePassword = "pass_for_self_signed_cert".toCharArray();

    // Bind the socket to the given port and address
    var serverSocket = getSslContext(keyStorePath, keyStorePassword)
            .getServerSocketFactory()
            .createServerSocket(address.getPort(), backlog, address.getAddress());

    // We don't need the password anymore → Overwrite it
    Arrays.fill(keyStorePassword, '0');

    return serverSocket;
}

private static SSLContext getSslContext(Path keyStorePath, char[] keyStorePass)
        throws Exception {

    var keyStore = KeyStore.getInstance("JKS");
    keyStore.load(new FileInputStream(keyStorePath.toFile()), keyStorePass);

    var keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
    keyManagerFactory.init(keyStore, keyStorePass);

    var sslContext = SSLContext.getInstance("TLS");
    // Null means using default implementations for TrustManager and SecureRandom
    sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
    return sslContext;
}

private static String getResponse(Charset encoding) {
    var body = "The server says hi ????\r\n";
    var contentLength = body.getBytes(encoding).length;

    return "HTTP/1.1 200 OK\r\n" +
            String.format("Content-Length: %d\r\n", contentLength) +
            String.format("Content-Type: text/plain; charset=%s\r\n",
                    encoding.displayName()) +
            // An empty line marks the end of the response's header
            "\r\n" +
            body;
}

private static List<String> getHeaderLines(BufferedReader reader)
        throws IOException {
    var lines = new ArrayList<String>();
    var line = reader.readLine();
    // An empty line marks the end of the request's header
    while (!line.isEmpty()) {
        lines.add(line);
        line = reader.readLine();
    }
    return lines;
}

Here's a project using this socket-based approach.

Multi-threaded

To use more than one thread for the server, you can employ a thread pool:

public static void startMultiThreaded(InetSocketAddress address) {

    try (var serverSocket = getServerSocket(address)) {

        System.out.println("Started multi-threaded server at " + address);

        // A cached thread pool with a limited number of threads
        var threadPool = newCachedThreadPool(8);

        var encoding = StandardCharsets.UTF_8;

        // This infinite loop is not CPU-intensive since method "accept" blocks
        // until a client has made a connection to the socket
        while (true) {
            try {
                var socket = serverSocket.accept();
                // Create a response to the request on a separate thread to
                // handle multiple requests simultaneously
                threadPool.submit(() -> {

                    try ( // Use the socket to read the client's request
                          var reader = new BufferedReader(new InputStreamReader(
                                  socket.getInputStream(), encoding.name()));
                          // Writing to the output stream and then closing it
                          // sends data to the client
                          var writer = new BufferedWriter(new OutputStreamWriter(
                                  socket.getOutputStream(), encoding.name()))
                    ) {
                        getHeaderLines(reader).forEach(System.out::println);
                        writer.write(getResponse(encoding));
                        writer.flush();
                        // We're done with the connection → Close the socket
                        socket.close();

                    } catch (Exception e) {
                        System.err.println("Exception while creating response");
                        e.printStackTrace();
                    }
                });
            } catch (IOException e) {
                System.err.println("Exception while handling connection");
                e.printStackTrace();
            }
        }
    } catch (Exception e) {
        System.err.println("Could not create socket at " + address);
        e.printStackTrace();
    }
}

private static ExecutorService newCachedThreadPool(int maximumNumberOfThreads) {
    return new ThreadPoolExecutor(0, maximumNumberOfThreads,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<>());
}

Create a certificate

Use the keytool to create a self-signed certificate (you can get a proper certificate from Let's Encrypt for free):

keytool -genkeypair -keyalg RSA -alias selfsigned -keystore keystore.jks \
        -storepass pass_for_self_signed_cert \
        -dname "CN=localhost, OU=Developers, O=Bull Bytes, L=Linz, C=AT"

Contact the server

After starting the server, connect to it with curl:

curl -k https://localhost:8443

This will fetch a message from the server:

The server says hi ????

Inspect which protocol and cipher suite were established by curl and your server with

curl -kv https://localhost:8443

Using JDK 13 and curl 7.66.0, this produced

SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384


Refer to Java Network Programming by Elliotte Rusty Harold for more on the topic.

尛丟丟 2024-08-29 19:43:36

虽然这个问题确实很老了,但有人向我提到了这个话题并问是否可以简化它。大多数答案都很好地演示了如何使用 sun 设置一个简单的 https 服务器,但我想提供一种替代方案,希望它更容易一些。

对于此设置,我假设您已经拥有密钥库和信任库。

其余端点:

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

public class HelloWorldController implements HttpHandler {

    @Override
    public void handle(HttpExchange exchange) throws IOException {
        try (OutputStream responseBody = exchange.getResponseBody()) {

            exchange.getResponseHeaders().set("Content-Type", "text/plain");

            String payload = "Hello";
            exchange.sendResponseHeaders(200, payload.length());
            responseBody.write(payload.getBytes(StandardCharsets.UTF_8));
        }
    }

}

服务器配置:

import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import nl.altindag.server.controller.HelloWorldController;
import nl.altindag.ssl.SSLFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

public class App {

    public static void main(String[] args) throws IOException {
        SSLFactory sslFactory = SSLFactory.builder()
                .withIdentityMaterial("keystore.jks", "secret".toCharArray())
                .withTrustMaterial("truststore.jks", "secret".toCharArray())
                .build();

        InetSocketAddress socketAddress = new InetSocketAddress(8443);
        HttpsServer httpsServer = HttpsServer.create(socketAddress, 0);

        httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslFactory.getSslContext()) {
            @Override
            public void configure(HttpsParameters params) {
                params.setSSLParameters(sslFactory.getSslParameters());
            }
        });

        httpsServer.createContext("/api/hello", new HelloWorldController());
        httpsServer.setExecutor(Executors.newCachedThreadPool());
        httpsServer.start();
    }

}

我需要在此处添加一些免责声明...我使用 Github - SSLContext-Kickstart 库可轻松构建 SSLContext。它是由我维护的。您不需要使用它,因为其他人提供了一种仅使用普通 java 来构造它的方法。

Although this question is really old, someone mentioned me this topic and asked if it could be simplified. Most of the answers demonstrate very well how to setup a simple https server with sun, but I want to provide an alternative which is hopefully a bit easier.

For this setup I am assuming you already have the keystore and truststore in place.

The rest endpoint:

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

public class HelloWorldController implements HttpHandler {

    @Override
    public void handle(HttpExchange exchange) throws IOException {
        try (OutputStream responseBody = exchange.getResponseBody()) {

            exchange.getResponseHeaders().set("Content-Type", "text/plain");

            String payload = "Hello";
            exchange.sendResponseHeaders(200, payload.length());
            responseBody.write(payload.getBytes(StandardCharsets.UTF_8));
        }
    }

}

Server configuration:

import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import nl.altindag.server.controller.HelloWorldController;
import nl.altindag.ssl.SSLFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

public class App {

    public static void main(String[] args) throws IOException {
        SSLFactory sslFactory = SSLFactory.builder()
                .withIdentityMaterial("keystore.jks", "secret".toCharArray())
                .withTrustMaterial("truststore.jks", "secret".toCharArray())
                .build();

        InetSocketAddress socketAddress = new InetSocketAddress(8443);
        HttpsServer httpsServer = HttpsServer.create(socketAddress, 0);

        httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslFactory.getSslContext()) {
            @Override
            public void configure(HttpsParameters params) {
                params.setSSLParameters(sslFactory.getSslParameters());
            }
        });

        httpsServer.createContext("/api/hello", new HelloWorldController());
        httpsServer.setExecutor(Executors.newCachedThreadPool());
        httpsServer.start();
    }

}

I need to add some disclaimer here... I use SSLFactory class from the Github - SSLContext-Kickstart library to easily construct a SSLContext. It is maintained by me. You don't need to use it as others have provided a way to construct it with just plain java.

忘年祭陌 2024-08-29 19:43:36

只是提醒其他人:上述解决方案中的 com.sun.net.httpserver.HttpsServer 不是 Java 标准的一部分。虽然它是 与 Oracle/OpenJDK JVM 捆绑,它并未包含在所有 JVM 中,因此这不会在任何地方开箱即用。

您可以将多种轻量级 HTTP 服务器嵌入到支持 HTTPS 并在任何 JVM 上运行的应用程序中。

其中之一是 JLHTTP - Java 轻量级 HTTP 服务器,它是一个小型单文件服务器(或~50K/35K jar),没有依赖项。设置密钥库、SSLContext 等与上面类似,因为它也依赖于标准 JSSE 实现,或者您可以指定标准系统属性来配置 SSL。您可以查看常见问题解答或代码及其文档了解详细信息。

免责声明:我是 JLHTTP 的作者。您可以亲自检查并确定它是否适合您的需求。我希望你觉得它有用:-)

Just a reminder to others: com.sun.net.httpserver.HttpsServer in the solutions above is not part of the Java standard. Although it is bundled with the Oracle/OpenJDK JVM, it is not included in all JVMs so this will not work out of the box everywhere.

There are several lightweight HTTP servers out there that you can embed in your application that support HTTPS and run on any JVM.

One of them is JLHTTP - The Java Lightweight HTTP Server which is a tiny one-file server (or ~50K/35K jar) with no dependencies. Setting up the keystore, SSLContext etc. is similar to the above, since it also relies on the standard JSSE implementation, or you can specify the standard system properties to configure SSL. You can see the FAQ or the code and its documentation for details.

Disclaimer: I'm the author of JLHTTP. You can check it out for yourself and determine if it suits your needs. I hope you find it useful :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文