springboot CXF 调用webservice客户端https+ip时跳过认证

 1、  JaxWsProxyFactoryBean 

   简介: 调用方式采用了和RMI类似的机制,即客户端直接服务器端提供的服务接口(interface),CXF通过运行时代理生成远程服务的代理对象,在客户端完成对webservice的访问; 几个必填的字段:setAddress-这个就是我们发布webservice时候的地址,保持一致

     缺点: 这种调用service的好处在于调用过程非常简单,就几行代码就完成一个webservice的调用,但是客户端也必须依赖服务器端的接口,这种调用方式限制是很大的,要求服务器端的webservice必须是java实现--这样也就失去了使用webservice的意义

public class Client {  
    public static void main(String[] args) {  
        JaxWsProxyFactoryBean bean = new JaxWsProxyFactoryBean();  
        bean.setServiceClass(HelloWorldService.class);  
        bean.setAddress("http://localhost:9090/helloWorldService");  
        HelloWorldService helloWorldService = (HelloWorldService)bean.create();  
        String result = helloWorldService.sayHello("Kevin");  
        System.out.println(result);  
    }
}

当调用的地址为https+ip时会抛出异常

Caused by: java.io.IOException: The https URL hostname does not match the Common Name (CN) on the server certificate in the client's truststore.  Make sure server certificate is correct, or to disable this check (NOT recommended for production) set the CXF client TLS configuration property "disableCNCheck" to true.

查看源码当发送数据到服务时用的是MessageSenderEndingInterceptor

public static class MessageSenderEndingInterceptor extends AbstractPhaseInterceptor {
        public MessageSenderEndingInterceptor() {
            super(Phase.PREPARE_SEND_ENDING);
        }

        public void handleMessage(Message message) throws Fault {
            try {
                getConduit(message).close(message);
            } catch (SocketTimeoutException e) {
                throw new Fault(new org.apache.cxf.common.i18n.Message("COULD_NOT_RECEIVE", BUNDLE), e);
            } catch (IOException e) {
                throw new Fault(new org.apache.cxf.common.i18n.Message("COULD_NOT_SEND", BUNDLE), e);
            }
        }
    }

    public static Conduit getConduit(Message message) throws IOException {
        Exchange exchange = message.getExchange();
        Conduit conduit = exchange.getConduit(message);
        if (conduit == null
            && (exchange.getOutMessage() != null
                || exchange.getOutFaultMessage() != null)) {
            conduit = OutgoingChainInterceptor.getBackChannelConduit(message);
        }
        return conduit;
    }
Conduit为HTTPConduit

需要设置HttpConduit的参数为跳过

JaxWsProxyFactoryBean创建代理类的时候默认用的是JaxWsClientFactoryBean.creat()方法
 public Client create() {
        getServiceFactory().reset();
        if (getServiceFactory().getProperties() == null) {
            getServiceFactory().setProperties(properties);
        } else if (properties != null) {
            getServiceFactory().getProperties().putAll(properties);
        }
        Client client = null;
        Endpoint ep = null;
        try {
            ep = createEndpoint();
            this.getServiceFactory().sendEvent(FactoryBeanListener.Event.PRE_CLIENT_CREATE, ep);
            applyProperties(ep);
            client = createClient(ep);
            initializeAnnotationInterceptors(ep, getServiceClass());
        } catch (EndpointException e) {
            throw new ServiceConstructionException(e);
        } catch (BusException e) {
            throw new ServiceConstructionException(e);
        }
        applyFeatures(client);
        this.getServiceFactory().sendEvent(FactoryBeanListener.Event.CLIENT_CREATED, client, ep);
        return client;
    }

想跳过证书验证需要对creat()方法进行增强

import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientFactoryBean;
import org.apache.cxf.jaxws.JaxWsClientFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;

import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @author zjx
 * @date 2022/7/8.
 */
public class ClientFactoryBeanImpl extends JaxWsClientFactoryBean {
    public Client create() {
        Client client = super.create();
        HTTPConduit conduit = (HTTPConduit)client.getConduit();
        TLSClientParameters params = conduit.getTlsClientParameters();

        if (params == null) {
            params = new TLSClientParameters();
            conduit.setTlsClientParameters(params);
        }
        params.setTrustManagers(new TrustManager[] {
                new TrustAllManager() });

        params.setDisableCNCheck(true);
        return client;

    }

    private class TrustAllManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }


        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Do Nothing
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

    }
}

在创建代理类时使用增强的JaxWsClientFactoryBean,在JaxWsProxyFactoryBean set进去

public class Client {  
    public static void main(String[] args) {  
        JaxWsProxyFactoryBean bean = new JaxWsProxyFactoryBean();
        bean.setClientFactoryBean(new ClientFactoryBeanImpl());  
        bean.setServiceClass(HelloWorldService.class);  
        bean.setAddress("http://localhost:9090/helloWorldService");  
        HelloWorldService helloWorldService = (HelloWorldService)bean.create();  
        String result = helloWorldService.sayHello("Kevin");  
        System.out.println(result);  
    }
}

这样就能成功调用https+ip的webservice服务了

你可能感兴趣的:(javaApi,大数据,java,https)