JAX-WS:使用 Apache CXF 创建自底向上 Web 服务、Web 服务客户端和保护 Web 服务





5.00/5 (8投票s)
我们将使用 Java 7 和 Apache CXF 框架在 Eclipse IDE 中实现 Web 服务和客户端。
引言
阅读本文并遵循示例后,读者应该能够创建一个自底向上(代码优先)的 SOAP Web 服务,以及一个利用该 Web 服务的客户端,同时实现消息级加密以保护消息有效负载。
背景
当我第一次接触 SOAP Web 服务时,我花了大量时间在互联网上搜索、阅读文章和查阅技术规范,希望能理解并最终能够连接到现有的 Web 服务以及搭建我自己的 Web 服务。 我在各种网站上零散地找到了一些信息,但一直希望找到一个单一的来源,它能提供一个我能理解的完整示例。 本文是我试图通过提供一个从零开始的教程来帮助其他第一次接触 SOAP Web 服务的开发者。
虽然我的目标是提供一个一致的 SOAP Web 服务示例,但我不会详细解释 SOAP 消息、WSDL 文件、Apache CXF 库或 WSS4J 库的大部分方面。 本文更侧重于“如何”完成,而不是对技术进行详细解释。
除了创建一个基本的 Web 服务和客户端之外,本文更进一步展示了如何加密 Web 服务消息有效负载,为 Web 服务提供消息级加密。 WS-Security 本身是一个复杂的主题,因此,同样,本文仅涵盖 WSS4J 对 SOAP 消息的 WS-Security 的基本用法。
环境
本文将使用 Eclipse IDE(Kepler)、Java 7 和 Apache CXF 框架来实现 Web 服务和客户端。 Apache Tomcat 将作为托管 Web 服务的 Web 服务器。 作为 Apache CXF 的替代方案,可以使用 Apache Axis 库,但就个人而言,我对 CXF 的经验更多。 互联网上的各种文章解释了 CXF 和 Axis 之间的区别。
Java
Java JDK 1.7.0_60
http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html
IDE
Eclipse Kepler Service Release 2
http://eclipse.org/downloads/packages/release/Kepler/SR2
Web 服务器
Apache Tomcat 7
https://tomcat.net.cn/download-70.cgi
Web 服务框架
Apache CXF 2.6.13
https://cxf.apache.org/cxf-2613-release-notes.html
WSS4J 1.6.16
http://archive.apache.org/dist/ws/wss4j/1.6.16/
创建自底向上 Web 服务
Web 服务可以通过两种方式创建:自顶向下或自底向上。
自顶向下 Web 服务以 WSDL(Web 服务描述语言)文件的创建开始,然后生成符合 WSDL 规定的 Java 代码。
自底向上 Web 服务以 Java 代码的创建开始,然后生成描述与 Java 代码交互所需的操作和消息的 WSDL 文件。
本文将重点介绍自底向上 Web 服务。 我认为这种方法比自顶向下服务创建更容易遵循,特别是对于不熟悉 SOAP 服务的新 Java 开发者来说。 本质上,我们将创建一个用 Java 编写的基本实用程序,它可以是独立应用程序的一部分,并利用 Web 服务框架将该实用程序公开为 Web 服务。
创建 Eclipse 项目
创建项目工作区
创建动态 Web 项目
创建将作为 Web 服务公开的逻辑
在本例中,我们将创建一个 MathUtility 类,它公开两个用于操作数字的方法。此逻辑本身没有什么特别之处或与 Web 服务相关;它很容易独立使用,不使用 SOAP Web 服务上下文。
在 Java Resources / src 目录下创建一个新包
在包下创建一个新类。 此类包含将作为 Web 服务操作公开的逻辑。
创建逻辑
package com.math.utility;
public class MathUtility {
public int addIntegers(int firstNum, int secondNum) {
return firstNum + secondNum;
}
public int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result = result * i;
}
return result;
}
}
Web 服务器配置
需要将 Apache Tomcat 服务器(将托管 Web 服务)配置到 Eclipse IDE 中。
单击 UI 底部的“Server”选项卡
选择“Create a New Server”,然后选择“Apache” - “Tomcat 7”
选择 Tomcat 安装目录
选择“Finish”。 Tomcat 现在已添加到 Servers 列表
Apache CXF 2.x 配置
需要将 Eclipse IDE 配置为使用 Apache CXF Web 服务框架来创建和通信 Web 服务。
选择“Window” - “Preferences” - “Web Services” - “CXF 2.x Preferences”。
在“CXF Runtime”下选择“Add”并找到您解压 CXF 库的位置
选择“Apply”和“Ok”以完成此步骤。
最后,在“Web Services”下的“Server and Runtime”中选择“Server and Runtime”,并将 Server Runtime 设置为 Tomcat 7。 Web Service Runtime 应设置为 Apache CXF 2.x。
选择“Apply”,然后选择“OK”完成。
创建 Web 服务
在创建了我们希望公开为服务的逻辑,并配置了 Eclipse 工作区以使用 Tomcat 和 CXF 后,我们就可以构建 Web 服务并运行它了。
右键单击 Java Resources – New – Web Service
“Browse”以选择要用于 Web 服务的 Service Implementation。 在本例中,将是“MathUtility”。
将滑块移至“Test Web Service”并选择“Finish”。
此时,Eclipse IDE 使用 Apache CXF 生成 WSDL 文件和相关模式,以基于 MathUtility 逻辑创建 Web 服务。 在创建了必要的文件之后,该工具会将这些文件添加到“WebContent”下的“wsdl”目录中。
Web 服务创建完成后,Web 服务将启动,并附带一个实用程序,允许我们验证逻辑是否已公开为 Web 服务并正常工作。
Web 服务器启动后,将出现一个 Web Services Explorer 窗口,其中包含服务详细信息。
如果选择一个 Operation,您就可以测试该服务。 在此示例中,选择“factorial”。 然后在一个文本框中输入一个数字。
选择“Go”,操作将被执行。 “Status”窗口显示 Web 服务调用的响应。
“MathUtility”中的逻辑现在已被公开为 SOAP Web 服务,部署在 Apache Tomcat Web 服务器上,并使用 Eclipse IDE 内置的 Web Services Explorer 功能进行了测试。
创建 Web 服务客户端
虽然 Web Services Explorer 允许我们与 Web 服务进行交互并测试功能,但为了以编程方式交互,需要创建一个 Web 服务客户端。 Web 服务客户端将是一个独立的 Java 应用程序。
创建 Eclipse 项目
在 Eclipse Project Explorer 中,右键单击并选择“New” - “Project” - “Java Project”
创建一个名为“MathUtilityClient”的项目
右键单击“src”并选择“New” - “Package”。 命名新的包。 该包最终将包含 Apache CXF 自动生成的与先前创建的 Web 服务交互的代码。
生成客户端存根
我们现在将使用 Apache CXF 分发版中包含的 wsdl2java 工具。 wsdl2java 工具将接收 WSDL 文档并生成用于与 WSDL 中定义的 Web 服务交互的 Java 代码。
打开命令提示符,导航到包含使用 Apache CXF 生成的 WSDL 的目录
现在,使用 wsdl2java 工具生成与 Web 服务交互所需的 Java 类。
"C:\Program Files (x86)\apache-cxf-2.6.13\apache-cxf-2.6.13\bin\wsdl2java.bat" -fe jaxws21 -autoNameResolution -p com.schema.mathutility -d "C:\Users\cjswidj2\Desktop\MathUtilityClient\generated" mathutility.wsdl
此示例中指定了几个选项。 最重要的是生成类的包名(-p)和文件的输出目录(-d)。 可以在 Apache CXF 网站上找到选项的完整列表:http://cxf.apache.org/docs/wsdl-to-java.html。
生成的类已创建并放置在我们执行 wsdl2java 命令时定义的目录中。
将所有生成的类从临时目录复制到之前创建的 MathUtilityClient 项目中的空 Eclipse 包。
调用 Web 服务
我们需要创建一个测试类,该类将使用生成的类连接到 MathUtility Web 服务并返回结果。
首先,配置客户端项目,使其在构建/类路径中包含 Apache CXF 库。
创建一个包来包含测试类。
创建带有 main 方法的类来运行我们的测试。
向 main 方法添加用于连接 SOAP Web 服务并执行操作的逻辑。
package com.mathutility.test;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.schema.mathutility.MathUtility;
public class TestMathUtility {
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
// Use the URL defined in the soap address portion of the WSDL
factory.setAddress("https://:8080/MathUtility/services/MathUtilityPort");
// Utilize the class which was auto-generated by Apache CXF wsdl2java
factory.setServiceClass(MathUtility.class);
Object client = factory.create();
try {
// Call the Web Service to perform an operation
int response = ((MathUtility)client).factorial(4);
System.out.println(response);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
运行测试类
客户端的控制台输出显示了服务的创建以及对服务的方法调用,以及服务的输出。
Apache Tomcat 控制台显示 SOAP 有效负载,包括来自 Web 服务服务器的入站和出站 SOAP 消息。
我们现在已连接到托管在 Apache Tomcat 服务器上的 SOAP Web 服务,并执行了该 Web 服务公开的操作。
保护 SOAP Web 服务
有几种方法可以保护 SOAP Web 服务,但本文将专门关注消息级加密。 消息级加密规定 SOAP 消息的某些部分从消息的源到消息的目的地都被加密。 为了为此 Web 服务提供消息级加密,我们将利用 Apache WSS4J 库来加密 Web 服务请求的有效负载。 具体来说,将加密 SOAP 消息的正文。
一个重要的注意事项是,在生产环境中应用消息级加密时,请求和相应的响应都可能被加密,从而在往返过程中保护消息的内容。
在本例中,我们将仅加密从 Web 服务客户端到 Web 服务的流量,展示基本的加密和解密。
创建公钥/私钥对
需要一对密钥才能在各自的位置加密和解密消息。
Apache CXF 网站提供了一个有关如何创建和打包 X.509 证书以用于 Web 服务安全的示例:http://cxf.apache.org/docs/ws-security.html。 我将重申基本步骤。
Java keytool 将用于生成密钥和操作密钥库。 如果“keytool”不在您的 PATH 中,您可以按如下方式设置它
set PATH=%PATH%;"C:\Program Files\Java\jdk1.7.0_60\bin"
创建公钥/私钥对并将私钥存储在密钥库中
keytool -genkey -alias testkey -keystore keystore.jks -storepass storepass -dname "cn=testkey" -keyalg RSA
从私钥库导出公钥
keytool -export -alias testkey -file publickey.rsa -keystore keystore.jks -storepass storepass
将公钥导入新的密钥库
keytool -import -alias testkey -file publickey.rsa -keystore clientkeystore.jks -storepass clientstorepass
执行这些步骤后,已创建两个密钥库
- clientkeystore.jks
- 公钥库将由 Web 服务客户端用于加密消息有效负载
- keystore.jks
- 私钥库将由我们的 Web 服务用于解密消息有效负载
配置客户端以加密消息
Apache CXF 依赖于 WSS4J“拦截器”来操作 Web 服务消息并应用安全。 拦截器本质上是一个 Java 类,它“捕获”Web 服务消息并根据配置提供的规范对其进行转换。
在客户端示例中,我们将通过编程方式在 main 方法中添加 WSS4J 拦截器。
在服务器示例中,WSS4J 拦截器配置将在 XML 文件(cxf-beans.xml)中提供。 CXF 将在内部使用 Spring 来加载配置文件并实例化必要的 WSS4J 类。
将密钥库添加到 Web 服务客户端项目
使用 keytool 创建的 clientkeystore.jks 文件复制到客户端项目中。
创建客户端密钥库属性文件
需要一个属性文件来指定要加载的密钥库文件以及有关该密钥库的属性。
clientKeystore.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.file=clientKeystore.jks
org.apache.ws.security.crypto.merlin.keystore.password=clientstorepass
org.apache.ws.security.crypto.merlin.keystore.type=jks
创建属性文件后,需要将其添加到客户端项目中。
创建密码回调类
尽管密钥库密码在密钥库属性文件中提供,但 WSS4J 要求访问密钥库的密码是通过使用 Password Callback 类加载的。 理想情况下,此类将从加密文件或其他数据存储中检索密码,而不是在类本身中硬编码值。
创建新的 Java 包
创建客户端密码回调类
package com.math.utility.security;
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 ClientPasswordCallback implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// set the password for our message.
pc.setPassword("clientstorepass");
}
}
以编程方式应用安全
对于我们的客户端,将通过编程方式添加 WSS4J 输出拦截器,而不是使用 Spring 依赖注入。 Java 代码将创建一个属性 Map,WSS4J 库需要这些属性,并使用这些属性实例化一个拦截器。
在示例代码中,我还添加了日志记录拦截器,它们将显示出站和入站消息。 log4j.properties 文件包含在项目源 .zip 文件中。
WSS4J 拦截器配置
作为参考,“ENCRYPTION_PARTS”属性的 WSS4J 拦截器指定了 SOAP 消息的哪些部分需要加密
// Set up WS-Security Encryption
// Reference: https://ws.apache.org/wss4j/using.html
Map<String, Object> props = new HashMap<String, Object>();
props.put(WSHandlerConstants.USER, "testkey");
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.ENCRYPT);
props.put(WSHandlerConstants.PASSWORD_TYPE, "PasswordText");
props.put(WSHandlerConstants.ENC_PROP_FILE, "clientKeystore.properties");
props.put(WSHandlerConstants.ENCRYPTION_PARTS, "{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body");
props.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName());
WSS4JOutInterceptor wss4jOut = new WSS4JOutInterceptor(props);
ClientProxy.getClient(client).getOutInterceptors().add(wss4jOut);
完整的客户端代码
package com.mathutility.test;
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.handler.WSHandlerConstants;
import com.math.utility.security.ClientPasswordCallback;
import com.schema.mathutility.MathUtility;
public class TestMathUtility {
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
// Use the URL defined in the soap address portion of the WSDL
factory.setAddress("https://:8080/MathUtility/services/MathUtilityPort");
// Utilize the class which was auto-generated by Apache CXF wsdl2java
factory.setServiceClass(MathUtility.class);
Object client = factory.create();
// Adding Logging Interceptors
LoggingOutInterceptor loggingOutInterceptor = new LoggingOutInterceptor();
loggingOutInterceptor.setPrettyLogging(true);
ClientProxy.getClient(client).getOutInterceptors().add(loggingOutInterceptor);
LoggingInInterceptor loggingInInterceptor = new LoggingInInterceptor();
loggingInInterceptor.setPrettyLogging(true);
ClientProxy.getClient(client).getInInterceptors().add(loggingInInterceptor);
// Set up WS-Security Encryption
// Reference: https://ws.apache.org/wss4j/using.html
Map<String, Object> props = new HashMap<String, Object>();
props.put(WSHandlerConstants.USER, "testkey");
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.ENCRYPT);
props.put(WSHandlerConstants.PASSWORD_TYPE, "PasswordText");
props.put(WSHandlerConstants.ENC_PROP_FILE, "clientKeystore.properties");
props.put(WSHandlerConstants.ENCRYPTION_PARTS, "{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body");
props.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName());
WSS4JOutInterceptor wss4jOut = new WSS4JOutInterceptor(props);
ClientProxy.getClient(client).getOutInterceptors().add(wss4jOut);
try {
// Call the Web Service to perform an operation
int response = ((MathUtility)client).factorial(4);
System.out.println(response);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
配置 Web 服务以解密消息
对于服务器端,WSS4J 配置通过 XML 文件(cxf-beans.xml)提供。 CXF 在内部使用 Spring 来加载配置文件并实例化必要的 WSS4J 类。
注意: 配置、密钥库和属性需要位于应用程序类路径上,因此请验证类路径设置以确保在运行时找到文件。
将私钥库添加到 Web 服务服务器项目
使用 keytool 创建的 keystore.jks 文件复制到服务器项目中。
创建用于使用密钥库的属性文件
需要一个属性文件来指定要加载的密钥库文件以及有关该密钥库的属性。
serverKeystore.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.file=keystore.jks
org.apache.ws.security.crypto.merlin.keystore.password=storepass
org.apache.ws.security.crypto.merlin.keystore.type=jks
创建属性文件后,需要将其添加到服务器项目中。
创建密码回调类
尽管密钥库密码在密钥库属性文件中提供,但 WSS4J 要求访问密钥库的密码是通过使用 Password Callback 类加载的。 理想情况下,此类将从加密文件或其他数据存储中检索密码,而不是在类本身中硬编码值。
创建新的 Java 包
创建服务器密码回调类
package com.math.utility.security;
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 ServerPasswordCallback implements CallbackHandler {
@Override
public void handle(Callback[] arg0) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) arg0[0];
// set the password for our message.
pc.setPassword("storepass");
}
}
更新配置文件以应用安全
现在必须更新 cxf-beans.xml 文件以包含为应用消息级安全而添加的相关组件。 这些更新包括引用密码回调类以及声明 WSS4J 拦截器。 作为参考,“decryptionParts”元素 WSS4J 拦截器指定了 SOAP 消息的哪些部分需要解密。
cxf-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.5.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="myPasswordCallback" class="com.math.utility.security.ServerPasswordCallback"/>
<jaxws:endpoint xmlns:tns="http://utility.math.com/" id="mathutility"
implementor="com.math.utility.MathUtility" wsdlLocation="wsdl/mathutility.wsdl"
endpointName="tns:MathUtilityPort" serviceName="tns:MathUtilityService"
address="/MathUtilityPort">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="user" value="testkey"/>
<entry key="action" value="Encrypt"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="decryptionParts" value="{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<entry key="decryptionPropFile" value="serverKeystore.properties"/>
<entry key="passwordCallbackRef">
<ref bean="myPasswordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
运行 Web 服务和客户端
一切配置完成后,现在可以启动 Web 服务并连接客户端了。
在“Server”选项卡下,右键单击 Tomcat Server 并选择“Start”。
一旦您看到“Started, Synchronized”,服务器已启动并完全初始化
接下来,导航到 MathUtilityClient 项目并运行 TestMathUtility 客户端
“Console”将显示 Web 服务客户端启动,向服务器发送 Web 服务请求,并接收响应。
由于代码还使用了 CXF 的 LoggingIn 和 LoggingOut 拦截器,我们可以访问 XML 消息的“美化打印”版本,清楚地显示加密的出站消息和明文 Web 服务响应。
出站 Web 服务请求
Jan 22, 2015 2:23:57 PM org.apache.cxf.services.MathUtilityService.MathUtilityPort.MathUtility
INFO: Outbound Message
---------------------------
ID: 1
Address: https://:8080/MathUtility/services/MathUtilityPort
Encoding: UTF-8
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1">
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="EK-D34D3D857E2A1163BA14219582374121">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=testkey</ds:X509IssuerName>
<ds:X509SerialNumber>79151085</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>ldC0JEkug/dwXejftXu9r9DmuvUeiU5Eq+L5OAAysHVFMUVOIWPV2FRfZ9rZcuiAefPbiGpj1eh5OG+Bx/GPITz+sTJ4xCLGLatAEdhBuP2iPeH/cfX8bNwLyGR1Fs71Q7pql1fySSNv/b+q/Yp7KUsxlKnVfFEJbAJc24O9uuzCUUXanHGOkMG/24HMbYEr25VjLCwcGdlqEOdeaIp88ywpse2luiULVvDiY7TA0U0C7/CY+PtRzN4j7OdyWwc9bp2etWvtT05cMiwcQPrb3ZM/w7/0g81Tgyhi/lFt6TGY1nf+Usd5kEeGX8bohkXAZWcq8oq2N1nJudRxycuKaw==</xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#ED-D34D3D857E2A1163BA14219582374282"/>
</xenc:ReferenceList>
</xenc:EncryptedKey>
</wsse:Security>
</SOAP-ENV:Header>
<soap:Body>
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-D34D3D857E2A1163BA14219582374282" Type="http://www.w3.org/2001/04/xmlenc#Content">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
<wsse:Reference URI="#EK-D34D3D857E2A1163BA14219582374121"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>Ww2p8p9K/Fdx3YDBDTcjwNCQFbUmBCcoaefFND9OwX24HP1FcDfRx91YQaDbmZSfqZGOlqgR0QZqKivp8kgT2I6z+mMbq8xwskRZg/OL7OuAG4BpmQloSq3ixHB0nlbJJ21s2itsCZMNYVtFNqTiBg==</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</soap:Body>
</soap:Envelope>
入站 Web 服务响应
Jan 22, 2015 2:23:58 PM org.apache.cxf.services.MathUtilityService.MathUtilityPort.MathUtility
INFO: Inbound Message
----------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Date=[Thu, 22 Jan 2015 20:23:58 GMT], Server=[Apache-Coyote/1.1], transfer-encoding=[chunked]}
Payload: <?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:factorialResponse xmlns:ns2="http://utility.math.com/">
<return>24</return>
</ns2:factorialResponse>
</soap:Body>
</soap:Envelope>
完成。
读者现在应该能够
- 使用 Apache CXF 创建 Web 服务
- 在 Tomcat 服务器上运行 Web 服务
- 创建客户端以使用 Apache CXF 利用 Web 服务
- 使用 WSS4J 保护客户端和服务器之间的消息有效负载