cxf+spring+数字签名开发webservice(一)
- 数字证书的准备
下面做的服务端和客户端证书在例子中无法加解密,不知道什么原因,我是使用正式环境中的客户端和服务端进行开发测试的,所以需要大家自己去准备证书,或者有人知道为什么jdk生成的一对证书无法加解密的原因那在好不过了。(例子中客户端和服务端都放在一起项目中,大家自己分开开发测试即可)下面是我用jdk生成的证书:
1.1、客户端
1、创建私钥和keystore
keytool -genkey -alias clientprivatekey -keypass keypass -keystore client.jks -storepass storepass -dname "CN=zs.com,C=CN" -keyalg RSA
2、自签名
keytool -selfcert -keystore client.jks -storepass storepass -alias clientprivatekey -keypass keypass
3、导出公钥到rsa
keytool -export -alias clientprivatekey -file client.rsa -keystore client.jks -storepass storepass
1.2、服务端
1、创建私钥和keystore
keytool -genkey -alias serverprivatekey -keypass keypass -keystore server.jks -storepass storepass -dname "CN=zs.com,C=CN" -keyalg RSA
2、自签名
keytool -selfcert -keystore server.jks -storepass storepass -alias serverprivatekey -keypass keypass
3、导出公钥到rsa
keytool -export -alias serverprivatekey -file server.rsa -keystore server.jks -storepass storepass
1.3、将服务端公钥加入客户端jks中
keytool -import -alias serverprivatekey -file server.rsa -keystore client.jks -storepass storepass
1.4、将客户端公钥加入服务端jks中
keytool -import -alias clientprivatekey -file client.rsa -keystore server.jks -storepass storepass
- 证书配置文件
2.1、客户端配置
jks文件放在ca包下,ca包直接在项目的src目录下,配置文件名称为client.properties(放在ca下),注意等号两边不要出现空格
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=证书的storepass
org.apache.ws.security.crypto.merlin.keystore.alias=证书的别名
org.apache.ws.security.crypto.merlin.file=ca/client.jks
2.2、服务端配置
jks文件放在ca包下,ca包直接在项目的src目录下,配置文件名称为server.properties(放在ca下),注意等号两边不要出现空格
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=storepass
org.apache.ws.security.crypto.merlin.keystore.alias=serverprivatekey
org.apache.ws.security.crypto.merlin.file=ca/server.jks
- 秘钥配置类
3.1、客户端
package cxf.test.client; import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback; public class UTPasswordClientCallBack implements CallbackHandler { @Override
public void handle(Callback[] callbacks) throws IOException,UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword("证书的keypass");
System.out.println("Client Identifier=" + pc.getIdentifier());
System.out.println("Client Password=" + pc.getPassword());
} }
3.2、服务端
package cxf.test.server; import java.io.IOException; import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; public class UTPasswordServerCallBack implements CallbackHandler { @Override
public void handle(Callback[] callbacks) throws IOException,UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword("证书的keypass");
System.out.println("Client Identifier=" + pc.getIdentifier());
System.out.println("Client Password=" + pc.getPassword());
} }
- 配置文件
4.1、web.xml配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value><!-- spring配置文件 -->
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern><!-- 匹配services/*后缀url -->
</servlet-mapping>
4.2、beans.xml配置(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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="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">
<!-- jar包中自带的cxf文件夹下的*.xml文件 -->
<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" />
<!-- 配置服务端方法所在的类及数字签名 -->
<jaxws:endpoint id="TestWebService" implementor="cxf.test.server.TestWebServiceImpl"
address="/wstest">
<!-- 通过拦截器对客户端发送的数据和签名进行解密处理 -->
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="Signature Encrypt" />
<entry key="signaturePropFile" value="ca/server.properties" />
<entry key="decryptionPropFile" value="ca/server.properties" />
<entry key="passwordCallbackClass" value="cxf.test.server.UTPasswordServerCallBack" />
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
<!-- 通过拦截器将服务端发送给客户端的数据和签名进行加密 -->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="Signature Encrypt" />
<entry key="user" value="服务端证书别名" />
<entry key="signatureUser" value="服务端证书别名" />
<entry key="signaturePropFile" value="ca/server.properties" />
<entry key="encryptionUser" value="useReqSigCert"></entry>
<entry key="decryptionPropFile" value="ca/server.properties" />
<entry key="passwordCallbackClass" value="cxf.test.server.UTPasswordServerCallBack" />
</map>
</constructor-arg>
<property name="allowMTOM" value="true"></property>
</bean>
</jaxws:outInterceptors>
</jaxws:endpoint>
</beans>
- 服务端类
5.1、接口类
package cxf.test.server; import javax.jws.WebParam;
import javax.jws.WebService; //配置targetNamespace,不进行配置,将使用当前类所在的包名顺序反向(如果这里没设置,默认命名空间为:http://server.test.cxf/)为命名空间。
//不进行命名空间设置,会存在客户端和服务端需要保持包名一致的问题,这在现实开发中肯定是很麻烦的事
@WebService(name = "TestWebService", targetNamespace = "http://cxf.test.tns/")
public interface TestWebService {
// 为了更好的兼容不同的开发语言、jdk版本等,接口方法的参数和返回结果最好是字符串,对象按xml格式进行编写和解析
// 接口方法的参数最好使用annotation设定接口方法的参数名,不进行设置,默认会在参数前加上“{”等符号(具体符号可能有误),
// 这样可能会给客户端调用带来不必要的麻烦,cxf有好几个annotation配置,如果客户端和服务端传递数据复杂类型参数时出现null等情况,一般进行相应annotation配置即可
public abstract String testMethod(@WebParam(name = "xml") String xml);
}
5.2、接口实现类
package cxf.test.server;
public class TestWebServiceImpl implements TestWebService {
public String testMethod(String xml) {
System.out.println(xml);
return "服务端被调用";
}
}
- 客户端类
6.1、接口类
package cxf.test.client; import javax.jws.WebParam;
import javax.jws.WebService; //使用annotation设置接口的命名空间。如果不进行设置,会出现客户端和服务端的接口类和bean类所在包名需保持一致的问题。出现对象作为参数
//或返回结果时为null的情况,不进行设置,默认按包名的反向顺序(如果该接口方法不进行设置,默认命名空间为:http://server.test.cxf/)作为命名空间
//最好是设置命名空间,包名暴露也不是好事
@WebService(name = "TestWebService", targetNamespace = "http://cxf.test.tns/")
public interface TestWebService {
// 为了更好的兼容不同的开发语言、jdk版本等,接口方法的参数和返回结果最好是字符串,对象按xml格式进行编写和解析
// 接口方法的参数最好使用annotation设定接口方法的参数名,不进行设置,默认会在参数前加上“{”等符号(具体符号可能有误),
// 这样可能会给客户端调用带来不必要的麻烦
public abstract String testMethod(@WebParam(name = "xml") String xml);
}
6.2、公共方法
package cxf.test.client; import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; /**
* 客户端调用服务端公共类
*
* @author yu
*
*/
public class Client {
/**
* 调用服务端接口时,先调用该方法,获得服务端接口方法,该方法设置数字签名的加解密信息
*
* @param address
* wsdl地址,包含“?wsdl”后缀
* @return
*/
public TestWebService call(String address) throws Exception {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(TestWebService.class);
factory.setAddress(address);
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("mtom-enabled", Boolean.TRUE);
factory.setProperties(properties);
// 客户端请求服务端时,客户端进行签名和加密,对应服务端请求拦截器。
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put("action", "Signature Encrypt");
outProps.put("user", "85e46503a2958c9137b832ebca4ee304_e9c397b2-2e69-4de0-8183-e978aa23b1d5");// 客户端证书别名
outProps.put("passwordCallbackClass",
UTPasswordClientCallBack.class.getName());
outProps.put("encryptionUser", "9598de1694450bdbe56ff58d7fa55cb9_e9c397b2-2e69-4de0-8183-e978aa23b1d5");// 服务端证书别名
outProps.put("encryptionPropFile", "ca/client.properties");// 客户端证书配置信息
outProps.put("signatureUser", "85e46503a2958c9137b832ebca4ee304_e9c397b2-2e69-4de0-8183-e978aa23b1d5");// 客户端证书别名
outProps.put("signaturePropFile", "ca/client.properties");
WSS4JOutInterceptor outInterceptor = new WSS4JOutInterceptor(outProps);
outInterceptor.setAllowMTOM(true);
factory.getOutInterceptors().add(outInterceptor);
// 服务端响应客户端请求时,客户端对服务端签名和加密进行处理,对应服务端响应拦截器
Map<String, Object> inProps = new HashMap<String, Object>();
inProps.put("action", "Signature Encrypt");
inProps.put("passwordCallbackClass",
UTPasswordClientCallBack.class.getName());
inProps.put("decryptionPropFile", "ca/client.properties");
inProps.put("signaturePropFile", "ca/client.properties");
factory.getInInterceptors().add(new WSS4JInInterceptor(inProps));
TestWebService webService = (TestWebService) factory.create();
return webService;
} }
6.3、测试
package cxf.test.client;
public class TestClient {
// 服务端wsdl地址,包含"?wsdl"后缀,wsdl地址一般放在数据库等地方,方便服务端改动时,客户端好更改.
private static String address = "http://127.0.0.1:7001/cxfserver/services/wstest?wsdl";
public static void main(String[] args) {
try {
Client client = new Client();
TestWebService webService = client.call(address);
String result = webService.testMethod("客户端调用服务端");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 说明
如果webservice的方法参数和返回值是xml(即将对象编写成xml作为参数传递),可以使用JiBx对对象和xml之间的转换做操作,可以参考下面文章:
http://www.ibm.com/developerworks/cn/java/tutorials/j-jibx1/
cxf+spring+数字签名开发webservice(一)的更多相关文章
- cxf+spring+数字签名开发webservice(二)
场景 上一章中的webservice接口,因为现场正式环境的项目与外部单位网络不通,是通过前置机与外部进行数据交换,所以我们将webservice部署在前置机,在使用HttpURLCo ...
- cxf + spring + maven 开发webservice
1.maven 配置 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://ww ...
- 解决cxf+spring发布的webservice,types,portType和message以import方式导入
用cxf+spring发布了webservice,发现生成的wsdl的types,message和portType都以import的方式导入的.. 原因:命名空间问题 我想要生成的wsdl在同个文件中 ...
- Spring Boot用Cxf的jax-ws开发WebService
首先上项目的pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&q ...
- Spring Boot 开发 WebService 服务
WebService 虽然现在大部分互联网企业不太提倡使用,但在以第三方接口为主导的市场,对方来什么接口你还得用什么接口,不可能把接口重写了.例如大部分传统的大型企业都在用 WebService,并且 ...
- CXF和Axis2开发webservice也是可以添加asmx等后缀
在当家互联网时代, 手机APP所需要的后台服务接口经常会变化, 如果前期没有设计好, 把它们的请求地址配置在比较稳定不会经常修改的地址(例如专门一个后台服务用于获取所有最新的数据服务地址)这样不会因为 ...
- CXF+Spring 搭建的WebService
1.创建类 2.接口编写 package com.fan; import javax.jws.WebService; @WebService public interface IHelloWorld ...
- Spring boot 开发WebService遇到的问题之一
当pom.xml文件中的配置: <artifactId>spring-boot-starter-parent</artifactId><version>2.0.6. ...
- 使用cxf开发webservice接口
项目中经常用到开发webservice接口,及调用webService接口.这里讲解如何使用cxf开发webService接口. 一.webservice介绍及理解 webservice是一种跨平台, ...
随机推荐
- 解决低版本chrome浏览器不支持es6 Array.find()
if (!Array.prototype.find) { Array.prototype.find = function(predicate) { 'use strict'; if ( ...
- 转载:NetBeans中如何运行GUI
这篇入门教程将教会您怎样创建一个简单的人机交互界面以及向其中添加简单 的后台功能. 特别地,我们将向您展示如何按 Swing 规范编写控制按钮和域代 码. 我们将会使用到布局管理.设计简单 GUI 界 ...
- easyui combobox点击输入框弹出下拉框
由于easyui combobox需要点击下拉箭头才能下拉,不能像select标签那样点击输入框就下拉,所以觉得不太方便,查看了一下,combobox弹出框是一个div,原本想在他的输入框的点击事件中 ...
- Flash导致弹出的div被隐藏
最近碰到一个问题,因为使用第三方的一个网页,那个网页是使用flash做的,我们在页面A中使用一个iframe导入他们的网页,页面A中有些按钮,点击弹出对应的弹出框,是easyui的模态弹出框.在我的浏 ...
- Loadrunner ---集合点设置
测试场景,实现用户登录的200并发: 1.录制登录退出脚本,且登录退出放aciton中 2.在登录的地方设置集合点 设置集合点有如下4中方式: 1)在要插入集合点的地方,右击鼠标按如下图操作:
- AFNetworking图片缓存问题
AFNetworking网络库已经提供了很好的图片缓存机制,效率是比较高的,但是我发现没有直接提供清除缓存的功能,可项目通常都需要添加 清除功能的功能,因此,在这里我以UIImageView+AFNe ...
- maven project 更新总是jre-1.5
解决如下: <build> <plugins> <plugin> <groupId>org.apa ...
- Interpreter(解释器)-类行为型模式
1.意图 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 2.动机 如果一种特定类型的问题发生的频率足够高,那么可能就值的将该问题的各个实例表述为一个 ...
- 使用dd命令克隆整个系统(转)
神奇的ghost的原理是什么呢?不就是数据复制吗?Linux下的dd命令不就是最强大的数据复制工具! 既然如此,我为什么要使用g4l这样复杂的工具呢?一条dd命令不就可以帮我实现任意 ...
- Erp中的ATP和CTP是什么?两者有什么区别?
可用量承诺(Available to Promise,ATP),是一种库存匹配模型,意在最大限度地利用库存产品对客户订单需求做出及时和准确的反应,缩短交货提前期.降低库存水准: 可用生产能力承诺(Ca ...