求带签名的SOAP请求完整Java代码(含导入及Maven依赖)
带WS-Security签名的SOAP请求完整实现
一、Maven依赖配置
添加必要依赖,基于Apache CXF实现WS-Security,BouncyCastle提供加密支持:
<dependencies> <!-- Apache CXF SOAP核心模块 --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>3.6.4</version> </dependency> <!-- CXF WS-Security安全模块 --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-ws-security</artifactId> <version>3.6.4</version> </dependency> <!-- BouncyCastle加密算法库 --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <!-- XML处理工具依赖 --> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> </dependency> </dependencies>
二、完整Java代码
以下代码包含XML读取、WS-Security签名/解密配置、SOAP请求发送,同时解决你遇到的XML解析显示[#document:null]的问题:
import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor; import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; import org.w3c.dom.Document; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.File; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; // 替换为实际SOAP服务生成的接口(可通过CXF wsdl2java工具生成) interface SoapService { String sendRequest(String xmlRequest); } public class SignedSoapClient { // 密钥库配置参数,替换为实际值 private static final String KEYSTORE_PATH = "C:\\Certificates\\Cert.jks"; private static final String KEYSTORE_PWD = "your-keystore-password"; private static final String CERT_ALIAS = "TestCert"; private static final String PRIVATE_KEY_PWD = "your-private-key-password"; public static void main(String[] args) throws Exception { // 1. 读取并解析XML请求文件(解决[#document:null]问题) Document requestDoc = readXmlFile("C:\\path\\to\\your\\request.xml"); String xmlRequest = convertDocToString(requestDoc); System.out.println("解析后的XML请求:\n" + xmlRequest); // 2. 创建CXF客户端代理 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setAddress("https://your-soap-service-endpoint.com"); factory.setServiceClass(SoapService.class); SoapService service = (SoapService) factory.create(); Client client = ClientProxy.getClient(service); // 3. 配置出站WS-Security(签名) Map<String, Object> outSecurityProps = new HashMap<>(); outSecurityProps.put("action", "Signature Timestamp"); // 签名核心配置 outSecurityProps.put("signatureKeyIdentifier", "DirectReference"); outSecurityProps.put("signatureUser", CERT_ALIAS); outSecurityProps.put("signaturePassword", PRIVATE_KEY_PWD); outSecurityProps.put("signatureKeystore", KEYSTORE_PATH); outSecurityProps.put("signatureStorePassword", KEYSTORE_PWD); // 算法配置 outSecurityProps.put("signatureAlgorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"); outSecurityProps.put("signatureCanonicalization", "http://www.w3.org/2001/10/xml-exc-c14n#"); outSecurityProps.put("signatureDigestAlgorithm", "http://www.w3.org/2001/04/xmlenc#sha512"); // 签名TimeStamp元素 outSecurityProps.put("signatureParts", "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp"); // 添加出站拦截器 client.getOutInterceptors().add(new SAAJOutInterceptor()); client.getOutInterceptors().add(new WSS4JOutInterceptor(outSecurityProps)); // 4. 配置入站WS-Security(解密) Map<String, Object> inSecurityProps = new HashMap<>(); inSecurityProps.put("action", "Decrypt"); inSecurityProps.put("decryptKeystore", KEYSTORE_PATH); inSecurityProps.put("decryptStorePassword", KEYSTORE_PWD); inSecurityProps.put("decryptPassword", PRIVATE_KEY_PWD); client.getInInterceptors().add(new WSS4JInInterceptor(inSecurityProps)); // 5. 发送请求并输出响应 String response = service.sendRequest(xmlRequest); System.out.println("服务响应:\n" + response); } // 读取XML文件为Document对象 private static Document readXmlFile(String filePath) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); // 必须启用命名空间支持,避免解析异常 DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(new File(filePath)); } // 将Document转换为字符串(解决直接打印显示[#document:null]的问题) private static String convertDocToString(Document doc) throws Exception { TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); StringWriter writer = new StringWriter(); transformer.transform(new DOMSource(doc), new StreamResult(writer)); return writer.getBuffer().toString(); } }
三、关键配置对应说明
出站签名配置
- 密钥库:通过
signatureKeystore指定C:\Certificates\Cert.jks路径 - 别名:
signatureUser设置为TestCert - 密钥标识符类型:
signatureKeyIdentifier设为DirectReference(对应Binary Security Token) - 签名算法:
signatureAlgorithm使用http://www.w3.org/2001/04/xmldsig-more#rsa-sha512(即rs-sha512) - 签名规范化:
signatureCanonicalization使用http://www.w3.org/2001/10/xml-exc-c14n#(即xml-exc-c14n#) - 摘要算法:
signatureDigestAlgorithm使用http://www.w3.org/2001/04/xmlenc#sha512(即xmlenc#sha512) - 签名部分:
signatureParts指定签名TimeStamp元素 - 单一证书:默认使用指定别名的单一证书,无需额外配置
入站解密配置
- 解密密钥库:通过
decryptKeystore指定C:\Certificates\Cert.jks路径
四、XML解析问题解决
你之前得到[#document:null]是因为直接打印Document对象的toString()结果,该方法不会输出XML内容。使用上述代码中的convertDocToString()方法,将Document转换为字符串即可查看完整XML内容。同时解析时需启用setNamespaceAware(true),避免因命名空间缺失导致后续签名失败。
内容的提问来源于stack exchange,提问作者Pradeep
相关产品推荐
相关产品推荐

