最近在做一个项目,两个异构系统中间需要进行数据交互,老大要求要保证安全性,数据交互方式初定为web service方式,用cxf实现。虽然CXF的WS-Security提供了比较全面的功能,但由于资料可以参考的资料太少,按照官方文档的试了一下没有跑通,就干脆自己做了一个。
异构系统之间的数据交互涉及到两个方面:
(1)传输的数据需要加密。比如从系统A向系统B发送了银行的账号和密码,这些信息是绝对不能在网络传输的过程中被截取到的。
(2)传输的系统间要建立信任关系。如果web service服务器发布了一个接收数据接口,是不能允许第三方不明身份的客户端调用这个接口的。
上述的两个安全性问题在所涉及的系统中,第二个问题比较重要,第一个问题只要不要明文出现就可以了,用一般的对称加密算法就可以了。所以问题的关键在于如何建立客户端和服务器端数据交换的数字证书。
对于数据的加密,目前比较公认的最保险的算法是非对称加密算法。基于非对称加密算法的思想,创建数字证书的思路为:客户端在调用服务器接口传输数据之前,先调用服务器端的一个接口,获取一个公钥;客户端用服务器端传输的公钥对一个共享密码进行加密,制造一个数字证书;服务器用自己保存的私钥和共享密码对证书进行验证。这样做有三个方面可以保证绝对保证安全:(1)服务器端每次产生的公钥和私钥对都是不同的、随机的;(2)共享密码是固定的,只有服务器端和被授权的客户端才知道,攻击方是不知道的;(3)共享密码制作的安全证书每次数据传输都是不同的,是不可伪造和修改无效的。
确定了方案,接下来只需要引入Srping的AOP功能,在客户端调用接口前系统执行安全相关的动作。相关代码如下:
web service 服务器端代码:
(1)服务器端产生公钥的接口:
import javax.jws.WebService;
@WebService
public interface ISignatureEncrp {
public String getIdentityKey()throws Exception;
}
(2)服务器端实现公钥的类
import javax.jws.WebService;
@WebService(endpointInterface = "com.wanmei.wmqc.exclusr.IPasswordEncrp")
public class PasswordEncrpImpl implements ISignatureEncrp{
public String getIdentityKey()throws Exception{
Object[] temp = RSAManager.generaterKey();
if(temp != null && temp.length>1){
ExcluServerConstants.KEY_PAIR_MAP.put(ExcluServerConstants.IDENTITY_KEY_PAIR, temp);
return new String((byte[])temp[1]);
}else{
return null;
}
}
}
(3)RSA算法具体实现类
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Random;
public class RSAManager {
public static Object[] generaterKey() throws Exception{
java.security.KeyPairGenerator keygen = java.security.KeyPairGenerator.getInstance("RSA");
SecureRandom secrand = new SecureRandom();
String seedsur = "abc"; // random seeds.
keygen.initialize(1024, secrand);
KeyPair keys = keygen.genKeyPair();
PublicKey pubkey = keys.getPublic();
PrivateKey prikey = keys.getPrivate();
byte[] pubKey = Base64.encodeToByte(pubkey.getEncoded());
byte[] priKey = Base64.encodeToByte(prikey.getEncoded());
Object[] result = new Object[2];
result[0] = pubKey;
result[1] = priKey;
return result;
}
public static byte[] sign(byte[] priKeyText, String plainText)throws Exception {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
Base64.decode(priKeyText));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey prikey = keyf.generatePrivate(priPKCS8);
java.security.Signature signet = java.security.Signature.getInstance("MD5withRSA");
signet.initSign(prikey);
signet.update(plainText.getBytes());
byte[] signed = Base64.encodeToByte(signet.sign());
return signed;
}
public static boolean verify(byte[] pubKeyText, String plainText, byte[] signText) throws Exception{
java.security.spec.X509EncodedKeySpec bobPubKeySpec =
new java.security.spec.X509EncodedKeySpec(Base64.decode(pubKeyText));
java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
java.security.PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);
byte[] signed = Base64.decode(signText);
java.security.Signature signatureChecker = java.security.Signature.getInstance("MD5withRSA");
signatureChecker.initVerify(pubKey);
signatureChecker.update(plainText.getBytes());
if (signatureChecker.verify(signed))
return true;
else
return false;
}
}
(4)beans.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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.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" />
<bean id="serverPasswordCallback"
class="com.**.**.exclusr.ServerPasswordCallback" />
<jaxws:endpoint id="exclusiveUser"
implementor="com.**.**.exclusr.ExclusiveUserImpl" address="/ExclUsr">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
<jaxws:endpoint id="signatureEncrp"
implementor="com.**.**.exclusr.SignatureEncrpImpl" address="/PwEncrp">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
web service客户端代码实现:
(1)公钥调用接口
import javax.jws.WebService;
@WebService
public interface ISignatureEncrp {
public String getIdentityKey()throws Exception;
}
(2)自动执行安全处理的切面类
import java.util.Iterator;
import java.util.List;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;
@Service
@Aspect
public class EncrptionAspect {
@Before("execution (* com.**.**.IExclusiveUser.sendSingleUser*(..)) && args(user,commPwd)")
public void doSingleUserFilter(UserInfo user,CommPwdInfo commPwd)throws Exception{
//初始化通讯密码:ExclusiveConstants.COMMUNICATION_PASSWORD
RSAManager.initEncrpClient();
commPwd.setCommunicationPwd(ExclusiveConstants.COMMUNICATION_PASSWORD);
}
}
(3)RSA实现类
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.List;
public class RSAManager {
public static byte[] sign(byte[] priKeyText, String plainText)throws Exception {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec
(Base64.decode(ExclusiveConstants.IDENTITY_PRIVATE_KEY.getBytes()));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey prikey = keyf.generatePrivate(priPKCS8);
java.security.Signature signet = java.security.Signature.getInstance("MD5withRSA");
signet.initSign(prikey);
signet.update(plainText.getBytes());
byte[] signed = Base64.encodeToByte(signet.sign());
return signed;
}
public static void initEncrpClient()throws Exception{
IPasswordEncrp iencrp = (IPasswordEncrp)ExclusiveConstants.APPLICATION_CONTEXT
.getBean(ExclusiveConstants.PASSWORD_ENCRP_INTERFACE);
try {
String priKey = iencrp.getIdentityKey();
ExclusiveConstants.IDENTITY_PRIVATE_KEY = priKey;
String password = new String(RSAManager.sign(priKey.getBytes(), ExclusiveConstants.IDENTITY_PASSWORD));
ExclusiveConstants.COMMUNICATION_PASSWORD = password;
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
(4)aop配置
<?xml version="1.0" encoding="UTF-8"?>
<!--
Application context definition for PetClinic on Hibernate.
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<context:component-scan base-package="com.**.**.exclusr"/>
<context:annotation-config/>
<aop:aspectj-autoproxy/>
</beans>
(5)client-beans.xml
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd" >
<jaxws:client id="pwEncrp"
serviceClass="com.**.**.exclusr.IPasswordEncrp"
address="http://127.0.0.1:8080/ws/PwEncrp" >
<!--If the LoggingOutInterceptor is useless for you, you can delete it. -->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</jaxws:outInterceptors>
<!-- End LoggingOutInterceptor -->
</jaxws:client>
<jaxws:client id="exclUsrClient"
serviceClass="com.**.**.exclusr.IExclusiveUser"
address="http://127.0.0.1:8080/ws/ExclUsr" >
<!--If the LoggingOutInterceptor is useless for you, you can delete it. -->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</jaxws:outInterceptors>
<!-- End LoggingOutInterceptor -->
</jaxws:client>
<bean id="clientPasswordCallback" class="com.**.**.exclusr.ClientPasswordCallback" />
</beans>
相关推荐
10. **cxf-rt-security.jar**: 提供Web服务的安全特性,如WS-Security等。 11. **cxf-rt-ws-policy.jar** 和 **cxf-rt-ws-addr.jar**: 支持WS-Policy(Web服务策略)和WS-Addressing(Web服务寻址)。 12. **cxf-...
7. **安全性**:CXF集成了多种安全机制,包括基本认证、Digest认证、WS-Security(用于消息级安全)等,确保服务的安全通信。 8. **工具和插件**:CXF提供了一系列的工具,如WSDL(Web服务描述语言)到Java代码生成...
2. **协议栈**:CXF提供了对各种Web服务标准的实现,包括SOAP 1.1/1.2、WS-Security、WS-Policy、WS-Addressing等。这些协议使得Web服务能够安全、可靠地进行通信。 3. **数据绑定**:CXF支持XML到Java对象的映射,...
1. **服务实现与调用**:CXF提供了两种方式来实现Web服务,即JAX-WS(Java API for XML Web Services)和JAX-RS(Java API for RESTful Web Services)。开发者可以通过注解或者XML配置文件轻松地将Java类绑定到Web...
5. **安全机制**:CXF支持多种安全模型,包括基本认证、 Digest认证、SSL/TLS、WS-Security(Web Services Security)等,确保服务的安全通信。 6. **拦截器与扩展点**:CXF的拦截器模型允许用户在服务调用的生命...
5. **安全机制**:CXF支持多种安全机制,如基本认证、WS-Security(Web Services Security)、OAuth等,确保Web服务的安全性。 6. **客户端和服务器端实现**:CXF提供了一套完整的工具集,用于创建Web服务的客户端...
- **丰富的模块**:CXF包括了许多可选模块,如Spring集成、WS-Security、数据绑定等,满足不同需求。 6. **使用场景**: CXF适用于需要创建高性能、高灵活性的Java Web服务的场合,无论是企业级应用还是小型项目...
8. **工具支持**:CXF提供了多种工具,如WSDL到Java的代码生成器,用于从WSDL文件自动生成服务接口和服务实现,还有WS-Security配置工具等。 在"apache-cxf-2.4.1"版本中,可能包含以下主要内容: 1. **库文件**:...
4. **WS-*支持**:CXF对Web服务标准如WS-Security、WS-Addressing和WS-Policy提供了全面的支持,使开发者能够构建安全、可靠的Web服务。 5. **代码生成**:CXF提供工具,如wsdl2java和cxf-codegen-plugin,可以自动...
- cxf-rt-ws-security.jar:WS-Security模块,实现安全相关的Web服务标准。 3. **依赖管理**:在实际项目中,使用CXF通常需要通过Maven或Gradle等构建工具来管理依赖关系,确保所有必要的JAR文件都被正确地引入到...
CXF的2.1版本在当时是一个稳定的版本,提供了许多关键改进和新特性,比如对JAXB 2.1的支持,增强的WS-Security实现,以及更好的WS-Addressing支持。这个版本还优化了性能,提高了开发者的生产力。 源码包中的目录...
- **WS-Security**:该版本包含了对WS-Security的实现,支持基于证书的身份验证和消息加密。 - **数据绑定**:CXF支持多种数据绑定技术,如JAXB、XOP和Aegis,方便将Java对象与XML消息相互转换。 - **传输和编码**:...
5. **WS-Security**:CXF实现了WS-Security规范,允许在Web服务中实现安全特性,如数字签名、加密、身份验证等。 6. **工具集**:CXF提供了一套强大的工具,如wsdl2java 和 java2wsdl,用于WSDL(Web Service ...
- JAX-WS(Java API for XML Web Services)库,是Java中的SOAP服务规范实现。 - HTTP客户端和服务器库,用于处理HTTP请求和响应。 - 安全相关的库,如WS-Security,用于处理加密、签名和身份验证。 - 日志库,如log...
- CXF支持WS-Security和其他安全标准,保护Web服务免受攻击。 - 它还实现了WS-I(Web Services Interoperability Organization)的基线规范,确保不同平台之间的互操作性。 总的来说,这个CXF 3.4.2的压缩包提供...
6. **安全功能**:CXF实现了各种安全标准,如WS-Security、WS-Trust和WS-SecureConversation,提供了基于证书和令牌的身份验证机制。 **2.7.4版本特点** 在Apache CXF 2.7.4版本中,开发者可以期待以下特性: - **...
Apache CXF是一个开源项目,它提供了多种功能来简化Web服务的开发,包括支持WS-*(如WS-Security, WS-ReliableMessaging等)标准、JAX-WS(Java API for XML Web Services)和JAX-RS(Java API for RESTful Web ...
这不仅涵盖了基本的Web服务概念,还包括了CXF特有的特性,如WS-Security(安全)、WS-ReliableMessaging(可靠消息传递)等。 为了更好地理解CXF的使用,你需要理解以下几个关键概念: - **JAX-WS**:Java API for...
CXF将服务端点接口(SEI,Service Endpoint Interface)与服务实现直接绑定,使得编码过程更加直观。此外,它还支持多种协议和格式,包括HTTP、HTTPS、JMS、SMTP等,并且可以处理SOAP、REST、JSON等多种数据格式。 ...
2. **WS-*协议支持**:CXF支持一系列WS-*协议,如WS-Security、WS-ReliableMessaging和WS-Addressing等,这些协议增强了Web服务的安全性、可靠性和交互性。 3. **多种绑定和数据格式支持**:CXF支持多种传输机制,...