【参考:http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html 】
【参考:http://cxf.apache.org/docs/configuration.html 】
前几节讲了http和jms的传输协议的实现,这节介绍如何使用https来实现通信。
一、生成密钥
要使用https通信,首先我们需要生成一个用于双方通信的密钥文件,可以使用java自带的keytool工具来生成,例如:
keytool -genkey -alias gliu -keyalg RSA -storepass liu123 -keypass liu123 -keystore gliu.jks -dname "CN=localhost"
如果不指定 -keystore 参数,则会在用户目录下生成一个.keystore 文件。另外这里-dname里的CN参数需要指定为你的website的名字,例如对于本地测试,则使用localhost。
二、接口定义
和前几节一样,接口定义很简单:
@WebService
public interface OrderProcess {
public String processOrder(Order order);
}
三、创建Service
要使得service支持https的传输协议,就需要用上面生成的密钥文件去配置服务引擎,首先在创建service时取得引擎对象:
JaxWsServerFactoryBean bean = new JaxWsServerFactoryBean();
Bus bus = bean.getBus();
JettyHTTPServerEngineFactory serverEngineFactory = bus
.getExtension(JettyHTTPServerEngineFactory.class);
然后就是配置引擎对象:
File file = new File("key/gliu.jks");
TLSServerParameters tlsParams = new TLSServerParameters();
KeyStore keyStore = KeyStore.getInstance("JKS");
String password = "liu123";
String storePassword = "liu123";
FileInputStream is = new FileInputStream(file);
keyStore.load(is, storePassword.toCharArray());
is.close();
KeyManagerFactory keyFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, password.toCharArray());
KeyManager[] keyManagers = keyFactory.getKeyManagers();
tlsParams.setKeyManagers(keyManagers);
TrustManagerFactory trustFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(keyStore);
TrustManager[] trustManagers = trustFactory.getTrustManagers();
tlsParams.setTrustManagers(trustManagers);
serverEngineFactory.setTLSServerParametersForPort(443, tlsParams);
最后创建服务即可:
bean.setAddress("https://localhost/security/order");
bean.setServiceBean(new OrderProcessImpl());
bean.setServiceClass(OrderProcess.class);
bean.create();
启动服务后就可以通过以下路径访问生成的wsdl了:
https://localhost/security/order?wsdl
也可以使用Spring配置,如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:jetty="http://cxf.apache.org/transports/http-jetty/configuration" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <jetty:engine-factory bus="cxf"> <jetty:engine port="443"> <jetty:tlsServerParameters> <sec:keyManagers keyPassword="liu123"> <sec:keyStore type="JKS" password="liu123" file="key/gliu.jks" /> </sec:keyManagers> </jetty:tlsServerParameters> </jetty:engine> </jetty:engine-factory> <jaxws:endpoint id="orderProcess" implementorClass="com.liulutu.liugang.https.OrderProcess" implementor="com.liulutu.liugang.https.OrderProcessImpl" address="https://localhost:443/security/order"> </jaxws:endpoint> </beans>
四、Client设置
一个简单的调用HTTPS服务的方式就是设置系统的ssl属性,例如调用上述service:
System.setProperty("javax.net.ssl.trustStore", "key/gliu.jks");
JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory
.newInstance();
Client client = factory
.createClient("https://localhost/security/order?wsdl");
Order order = new Order();
order.setId("helloId");
Object[] invokeWrapped = client.invoke("processOrder", order);
System.out.println(invokeWrapped[0]);
也可以通过配置HTTPConduit对象来调用,例如:
//create and configure client bean
JaxWsClientFactoryBean jwcfb = new JaxWsClientFactoryBean();
jwcfb.setServiceClass(OrderProcess.class);
jwcfb.setAddress("https://localhost/security/order");
Client client = jwcfb.create();
//configure conduit
HTTPConduit conduit = (HTTPConduit) client.getConduit();
configureSecurityInfoFor(conduit);
//invoke
Order order = new Order();
order.setId("helloId");
Object[] invokeWrapped = client.invoke("processOrder", order);
System.out.println(invokeWrapped[0]);
其中configureSecurityInfoFor(conduit)方法实现如如下:
TLSClientParameters tlsClientParameters = new TLSClientParameters();
tlsClientParameters.setSecureSocketProtocol("SSL");
FileInputStream is = new FileInputStream("key/gliu.jks");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(is, "liu123".toCharArray());
is.close();
//set trust keystore
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
tlsClientParameters.setTrustManagers(trustManagerFactory
.getTrustManagers());
//set keystore
KeyManagerFactory keyFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, "liu123".toCharArray());
tlsClientParameters.setKeyManagers(keyFactory.getKeyManagers());
conduit.setTlsClientParameters(tlsClientParameters);
也可以使用Spring配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:http-conf="http://cxf.apache.org/transports/http/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xsi:schemaLocation=" http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <http-conf:conduit name="*.http-conduit"> <http-conf:tlsClientParameters secureSocketProtocol="SSL"> <sec:keyManagers keyPassword="liu123"> <sec:keyStore type="JKS" password="liu123" file="key/gliu.jks" /> </sec:keyManagers> <sec:trustManagers> <sec:keyStore type="JKS" password="liu123" file="key/gliu.jks" /> </sec:trustManagers> </http-conf:tlsClientParameters> </http-conf:conduit> <jaxws:client id="orderProcessClient" serviceClass="com.liulutu.liugang.https.OrderProcess" address="https://localhost:443/security/order"> </jaxws:client> </beans>然后在java代码里:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/com/liulutu/liugang/https/client.xml");
OrderProcess bean = context.getBean("orderProcessClient", OrderProcess.class);
Order order = new Order();
order.setId("hello");
String processOrder = bean.processOrder(order);
System.out.println(processOrder);