Https Webservice接口的免证书调用

在调用https协议的Webservice接口时,如果没有做证书验证,一般会报 javax.net.ssl.SSLHandshakeException错误,如果是Was中间件,更会产生jar依赖问题。

一般的解决方案是利用jdk的keytool(ikeyman)生成公钥并导入进jre的信任公钥库中。这种方法略显繁琐复杂。

本文以 Axis、httpclient(其他客户端同理)调用方式为例,说明在不导入证书的情况下如何绕过验证调用Https协议的Webservice接口,适用于Sun/Oracle JDK和IBM JDK(was中间件)。

client发起https调用时,会使用默认的SocketFactory,对服务端证书进行验证,由于没有正确的公钥验签,是无法握手成功的。因此,对于自签名的服务端,我们需要重写一个SocketFactory,跳过证书验证,并用这个SocketFactory替换client本身默认的SocketFactory。这种方案不仅适用于Webservice框架的客户端,亦常用于Httpclient发起的https调用。

Axis调用

在调用Webservice接口时,替换axis.socketSecureFactory。

使用Sun/Oracle JDK的情况下可以直接用如下替换:

AxisProperties.setProperty("axis.socketSecureFactory","org.apache.axis.components.net.SunFakeTrustSocketFactory");

也可以写一个自定义的SocketFactory类进行替换(同时适用于IBM JDK):继承Axis的父类JSSESocketFactory ,并且重写父类initFactory方法

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Hashtable;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.axis.components.net.JSSESocketFactory;

/**
 * 跳过HTTPS验证
 * @since 2022-06-09
 */
public class MyTLSSocketSecureFactory extends JSSESocketFactory {

    public MyTLSSocketSecureFactory(Hashtable attributes) {
        super(attributes);
        // TODO Auto-generated constructor stub
    }

    // Create a trust manager that does not validate certificate chains

    X509TrustManager trustManager = new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] xcs, String str) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] xcs, String str) {
        }
    };
    TrustManager[] trustAllCerts = new TrustManager[] { trustManager };

    @Override
    public void initFactory() throws IOException {
        SSLContext ctx;
        try {
            ctx = SSLContext.getInstance("TLSv1.2");
//          ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            ctx.init(null, trustAllCerts, null);
            // ctx.init(null, trustAllCerts, new java.security.SecureRandom());
            sslFactory = ctx.getSocketFactory();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在调用前设置:

// 在客户端的ServiceSoapBindingStub.createCall()中设置
AxisProperties.setProperty("axis.socketSecureFactory", MyTLSSocketSecureFactory.class.getName());

Webservice接口调用:

try {
    URL endpoint = new URL("https://host:port/WebService?wsdl");
    webservice = new WebServiceLocator().getWebServicePort(endpoint);
} catch (Exception e) {
    e.printStackTrace();
}

HttpClient调用

可以使用Httpclient作为Webservice客户端发起免征书调用,优点是兼容性更强,缺点是需要自定义封装和解析soap xml报文。

Httpclient依赖jar: httpcore-4.4.4.jar,httpclient-4.5.jar(在was中间件下需要设置共享库,否则会发生jar冲突)

可以通过soapUI调试Webservice接口,获取调用时发送的soap xml格式。

     /**
     * 在调用SSL之前需要重写验证方法,取消检测SSL
     * 创建ConnectionManager,添加Connection配置信息
     * @return HttpClient 支持https
     */
    private static HttpClient getHttpClient() {
        try {
            // 在调用SSL之前需要重写验证方法,取消检测SSL
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String str) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String str) {
                }
            };
            SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            ctx.init(null, new TrustManager[] { trustManager }, null);
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
            // 创建Registry
            RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).setExpectContinueEnabled(Boolean.TRUE)
                    .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
                    .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).build();
            Registry socketFactoryRegistry = RegistryBuilder. create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE).register("https", socketFactory).build();
            // 创建ConnectionManager,添加Connection配置信息
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager)
                    .setDefaultRequestConfig(requestConfig).build();

            return closeableHttpClient;
        } catch (KeyManagementException ex) {
            throw new RuntimeException(ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException(ex);
        }
    }
    public static String doPost(String url, String soapXml, String soapAction) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        String result = "";
        // 创建httpClient实例
        httpClient = (CloseableHttpClient) getHttpClient();

        // 创建httpPost远程连接实例
        HttpPost httpPost = new HttpPost(url);

        // 设置请求头
        httpPost.addHeader("Content-Type", "text/xml;charset=UTF-8");
        httpPost.setHeader("SOAPAction", SOAPAction);
        httpPost.setEntity(new StringEntity(soapXml, "UTF-8"));

        try {
            // httpClient对象执行post请求,并返回响应参数对象
            httpResponse = httpClient.execute(httpPost);
            // 从响应对象中获取响应内容
            HttpEntity entity = httpResponse.getEntity();
            result = EntityUtils.toString(entity);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
            Logger.error("发送POST请求异常:" + e.getMessage(), e);
        } catch (IOException e) {
            e.printStackTrace();
            Logger.error("发送POST请求异常:" + e.getMessage(), e);
        } finally {
            // 关闭资源
            if (null != httpResponse) {
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

Original: https://www.cnblogs.com/yaenli/p/16480671.html
Author: YaenLi
Title: Https Webservice接口的免证书调用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/607836/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球