环境信息:CXF2.7 Spring3.1 tomcat6.0
一、创建webservice接口
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <!-- spring需要加载的配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:com/server/spring-cxf.xml </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- cxf服务启动servlet --> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>spring-cxf.xml
<?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:tx="http://www.springframework.org/schema/tx" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:cxf="http://cxf.apache.org/core" xmlns:wsa="http://cxf.apache.org/ws/addressing" xsi:schemaLocation=" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.1.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.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" /> <!-- <cxf:bus> <cxf:features> 日志拦截功能,用于监控soap内容,开发后可以删除 <cxf:logging/> <wsa:addressing/> </cxf:features> </cxf:bus> --> <bean id="hello" class="com.server.HelloWorldImpl" /> <jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld" publish="true"/></beans>HelloWorld.java
package com.server;
import javax.jws.WebService;/** * Web Service 接口声明 */@WebService(targetNamespace = "server.com")public interface HelloWorld { /** * sayHi * text * */ String sayHi(String text);}HelloWorldImpl.java
package com.server;import javax.jws.WebService;/** * Web Service接口实现 * */@WebService(endpointInterface = "com.server.HelloWorld")public class HelloWorldImpl implements HelloWorld { @Override public String sayHi(String text) { // TODO Auto-generated method stub return "Hello, " + text; }}部署代码后可在浏览器打开
此时webservice接口开发完成!
二、添加SSL双向认证
利用JDK自带keytool工具:直接cmd后执行:
keytool -genkey -alias test -keyalg RSA -keystore test.keystore -validity 3650
名字和姓氏要填域名或者IP名:服务器端IP。其他可以随便填
这步操作以后,得到test.keystorekeytool -export -alias test -file test.cer -keystore test.keystore 得到一个test.cer,然后把test.cer给到客户端,客户端用以下命令: keytool -import -alias test -file test.cer -keystore server.keystore 得到server.keystore,把这个文件作为客户端代码的truststore,才能正常访问到。可以理解为因为是用代码 来访问服务端,没有用户手工确认的过程,所以需要把证书加进来进行确认
那本地想要调用到服务端,就也需要做证书,同样先用这个命令: keytool -genkey -alias test1 -keyalg RSA -keystore test1.keystore -validity 3650
名字和姓氏要填域名或者IP名:客户端IP。其他可以随便填 得到test1.keystore 然后: keytool -export -alias test1 -file test1.cer -keystore test1.keystore 得到test1.cer,把test1.cer发给服务端,服务端用以下命令: keytool -import -alias test1 -file test1.cer -keystore client.keystore 得到了client.keystore,这里面就包含了客户端IP地址信息的证书信息,可以用以下命令查看: keytool -list -v -keystore client.keystore
配置tomcat-》conf-》server.xml
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS" keystoreFile="conf/test.keystore"
keystorePass="密码口令" keystoreType="jks" truststoreFile="conf/client.keystore"
truststorePass="密码口 令" truststoreType="jks" />
客户端调用代码:ClientTest.java
package com.client;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.server.HelloWorld;import com.util.ClientUtils;/** * 客户端访问服务器Web Service * */public final class ClientTest { public static void main(String args[]) throws Exception { HelloWorld client = ClientUtils.getInstance(); String response = client.sayHi("Joe"); System.out.println("Response: " + response); System.exit(0);}
}ClientUtils.javapackage com.util;
import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.security.KeyStore;import javax.net.ssl.KeyManager;import javax.net.ssl.KeyManagerFactory;import javax.net.ssl.TrustManager;import javax.net.ssl.TrustManagerFactory;import org.apache.cxf.configuration.jsse.TLSClientParameters;import org.apache.cxf.endpoint.Client;import org.apache.cxf.frontend.ClientProxy;import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;import org.apache.cxf.transport.http.HTTPConduit;import com.server.HelloWorld;public class ClientUtils { private static HelloWorld helloWorld; public static HelloWorld getInstance(){ if(null != helloWorld){ return helloWorld; } try{ String addr = "https://localhost:8443/cxf-demo/service/HelloWorld"; JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean(); factoryBean.setAddress(addr); factoryBean.setServiceClass(HelloWorld.class); helloWorld = (HelloWorld) factoryBean.create(); Client proxy = ClientProxy.getClient(helloWorld); HTTPConduit conduit = (HTTPConduit) proxy.getConduit(); TLSClientParameters tlsParams = conduit.getTlsClientParameters(); if (tlsParams == null) { tlsParams = new TLSClientParameters(); } tlsParams.setDisableCNCheck(true); //设置keystore tlsParams.setKeyManagers(ClientUtils.getKeyManagers()); // 设置信任证书 tlsParams.setTrustManagers(ClientUtils.getTrustManagers()); conduit.setTlsClientParameters(tlsParams); }catch(Exception e){ e.printStackTrace(); } return helloWorld; } public static KeyManager[] getKeyManagers() { InputStream is = null; try { // 获取默认的 X509算法 String alg = KeyManagerFactory.getDefaultAlgorithm(); // 创建密钥管理工厂 KeyManagerFactory factory = KeyManagerFactory.getInstance(alg); File certFile = new File("D://cer//222.keystore"); if (!certFile.exists() || !certFile.isFile()) { return null; } is = new FileInputStream(certFile); // 构建以证书相应格式的证书仓库 KeyStore ks = KeyStore.getInstance("JKS"); // 加载证书 ks.load(is, "qfkj2015".toCharArray()); factory.init(ks, "qfkj2015".toCharArray()); KeyManager[] keyms = factory.getKeyManagers(); return keyms; } catch (Exception e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } public static TrustManager[] getTrustManagers() { // 读取证书仓库输入流 InputStream is = null; try { // 信任仓库的默认算法X509 String alg = TrustManagerFactory.getDefaultAlgorithm(); // 获取信任仓库工厂 TrustManagerFactory factory = TrustManagerFactory.getInstance(alg); // 读取信任仓库 is = new FileInputStream(new File("D://cer//server.keystore")); // 密钥类型 KeyStore ks = KeyStore.getInstance("JKS"); // 加载密钥 ks.load(is, "qfkj2015".toCharArray()); factory.init(ks); TrustManager[] tms = factory.getTrustManagers(); return tms; } catch (Exception e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; }}