【问题标题】:Websocket with Client Certificate带有客户端证书的 Websocket
【发布时间】:2026-02-11 13:30:01
【问题描述】:

我有一个使用 javax.websocket 库的 Java websocket 客户端,目前看起来像这样:

WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.setDefaultMaxTextMessageBufferSize(BUFFER_SIZE);
container.connectToServer(this, ENDPOINT_URI);

现在我有一个要求,即客户端需要向服务器提供客户端证书。这如何实现?

【问题讨论】:

    标签: java websocket


    【解决方案1】:

    我找到了解决方案,所以我回答了我自己的问题:

    可以使用 ClientEndpointConfig 配置 WebsocketContainer。这允许设置自定义 SSLContext。然后客户端证书必须附加到 SSLContext。代码:

    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    container.setDefaultMaxTextMessageBufferSize(BUFFER_SIZE);
    container.connectToServer(new PojoEndpointClient(this, new ArrayList<>()), createClientConfig(), endpointURI);
    

    ClientEndpointConfig 可以这样构造:

    private ClientEndpointConfig createClientConfig() throws KeyManagementException, UnrecoverableKeyException,
     NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
        ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
        ClientEndpointConfig config = builder.decoders(new ArrayList<>()).encoders(new ArrayList<>())
                .preferredSubprotocols(new ArrayList<>()).build();
        SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(clientCert.toFile(), clientCertPassword,
                clientCertPassword, (aliases, socket) -> aliases.keySet().iterator().next()).build();
        config.getUserProperties().put(Constants.SSL_CONTEXT_PROPERTY, sslContext);
        return config;
    }
    

    这将在建立 websocket 连接时向服务器提供客户端证书。

    【讨论】:

    • Constants.SSL_CONTEXT_PROPERTY 在实现该方法时丢失。你用的是什么库?
    • 它来自 Apache Tomcat:org.apache.tomcat.websocket.Constants
    • 请注意,SSLContexts.custom() 在最近的版本中不存在,而是使用来自org.apache.httpcomponents:httpcoreorg.apache.http.ssl.SSLContextBuilderjava SSLContext sslContext = SSLContextBuilder .create() .loadKeyMaterial(new File(p12File), p12Password, p12Password) .build(); clientConfig.getUserProperties().put(Constants.SSL_CONTEXT_PROPERTY, sslContext);
    【解决方案2】:

    我不确定你在说什么证书,但可能你的意思是SSL/TLS 证书。在这种情况下,您只需要使用 wss 客户端(例如 nv-websocket-client),它将在后台处理所有 ssl/tls。

    另见答案:minimal java8 nio secure websocket client (wss)

    【讨论】:

    • SSL/TLS 不是问题。我们已经使用 wss 进行连接。但另外,我需要提供客户端证书。
    最近更新 更多