如何让 Jersey 客户端使用 HttpsURLConnection 中设置的 defaultSSLSocketFactory?

Posted

技术标签:

【中文标题】如何让 Jersey 客户端使用 HttpsURLConnection 中设置的 defaultSSLSocketFactory?【英文标题】:How to let Jersey client use the defaultSSLSocketFactory set in HttpsURLConnection? 【发布时间】:2016-11-26 21:51:35 【问题描述】:

我有一个项目,其中 HttpsURLConnection 被配置为使用自定义的 TrustManager,如下所示:

SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]new MyTrustManager(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

本项目中有一个 REST API 客户端,它使用 Jersey 客户端发送 HTTP/HTTPS 请求:

Client client = ClientBuilder.newClient();

但是,这个 Jerset 客户端发起的 HTTPS 连接没有使用我在 HttpsURLConnection 中设置的 defaultSSLSocketFactory 并且无法连接到不受信任的 HTTPS url。

我需要在此客户端上显式设置 SslContext 以使其与我的 TrustManager 一起使用。

SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]new MyTrustManager(), null);
Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();

有没有办法解决这个问题?

谢谢。

【问题讨论】:

***.com/questions/2145431/https-using-jersey-client 会回答这个问题吗? 没有。那篇文章讲授了如何通过 Jersey 向 HTTPS URL 发送请求。我知道如何做到这一点(如上一个 sn-p 所示)。我不知道的是如何让 Jersy 客户端使用我在 HttpsURLConnection 中设置的 SslContext。我想这样做的原因是我无权编辑 REST API 客户端代码以在 Jersey 客户端上显式设置 SslContext。 【参考方案1】:

我最终找到的解决方案是将 SSLSocketFactory 提供程序属性设置为自定义的 SSLSocketFactory。希望这可以帮助有类似问题的其他人。

在程序开始时调用它:

Security.setProperty("ssl.SocketFactory.provider", MySSLSocketFactory.class.getCanonicalName());

这是 MySSLSocketFactory 的样子(它还设置连接超时):

public class MySSLSocketFactory extends SSLSocketFactory 

    private SSLContext sslContext = SSLContext.getInstance(Const.Ssl.PROTOCOL_SSL);


    public MySSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException 
        this.sslContext.init(
                null,
                new TrustManager[]  new MyTrustManager(false) ,
                new SecureRandom());
    


    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
            throws IOException 
        socket.connect(new InetSocketAddress(host, port), Const.Ssl.CONNECT_TIMEOUT);
        socket.setSoTimeout(Const.Ssl.DATA_TIMEOUT);
        return this.sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    


    @Override
    public String[] getDefaultCipherSuites() 
        return this.sslContext.getSocketFactory().getDefaultCipherSuites();
    


    @Override
    public String[] getSupportedCipherSuites() 
        return this.sslContext.getSocketFactory().getSupportedCipherSuites();
    


    @Override
    public Socket createSocket(String host, int port)
            throws IOException, UnknownHostException 
        return this.createSocket(new Socket(), host, port, true);
    


    @Override
    public Socket createSocket(InetAddress address, int port)
            throws IOException 
        return this.createSocket(new Socket(), address.getHostAddress(), port, true);
    


    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
            throws IOException, UnknownHostException 
        return this.createSocket(new Socket(), host, port, true);
    


    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
            throws IOException 
        return this.createSocket(new Socket(), address.getHostAddress(), port, true);
    

【讨论】:

以上是关于如何让 Jersey 客户端使用 HttpsURLConnection 中设置的 defaultSSLSocketFactory?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jersey 客户端中默认使用 Genson 提供程序?

如何让OkHttp从Jersey获取参数并在Interceptor中使用?

如何强制 java SSLContext 使用 TLSv1.1

如何让我的Jersey 2端点在启动时急切地初始化?

如何在不手动转换为 JSON 的情况下使用 Jersey 客户端发布 Pojo?

如何使用 JAX-RS 和 Jersey 处理 CORS