You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java环境下调用带WS-Security的SOAP WebService签名问题咨询

实现WS-Security签名的分步解决方案(基于JAXB)

当然可以搞定!WS-Security的签名确实是SOAP服务调用里容易卡壳的环节,尤其是你已经用JAXB搞定了信封生成的情况下,咱们一步步来拆解,帮你把签名这块打通:

第一步:引入必要的依赖

XML数字签名的逻辑手写太容易出错,咱们直接用成熟的Apache Santuario库来处理。如果用Maven,添加以下依赖:

<dependency>
    <groupId>org.apache.santuario</groupId>
    <artifactId>xmlsec</artifactId>
    <version>2.2.3</version> <!-- 建议用最新稳定版 -->
</dependency>

第二步:准备密钥与证书

签名需要私钥(你用来签名),服务端验证需要对应的公钥证书。如果是测试阶段,可以用keytool生成密钥库:

keytool -genkeypair -alias my-service-key -keyalg RSA -keystore my-keystore.jks -storepass my-store-pass -keypass my-key-pass

然后在代码中加载私钥和证书:

// 加载密钥库
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream("my-keystore.jks"), "my-store-pass".toCharArray());

// 获取私钥和证书
PrivateKey privateKey = (PrivateKey) keyStore.getKey("my-service-key", "my-key-pass".toCharArray());
X509Certificate cert = (X509Certificate) keyStore.getCertificate("my-service-key");

第三步:给JAXB生成的SOAP信封添加签名

首先把JAXB生成的SOAP对象转换成DOM文档(因为XML签名需要操作DOM节点):

JAXBContext jaxbContext = JAXBContext.newInstance(YourSoapEnvelopeClass.class);
Marshaller marshaller = jaxbContext.createMarshaller();
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
marshaller.marshal(yourGeneratedSoapEnvelope, doc);

接下来创建WS-Security的签名,并把它插入到SOAP Header的wsse:Security节点中:

// 初始化XML签名工厂
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");

// 配置签名的引用(对整个SOAP信封进行签名,用ENVELOPED变换)
Reference signatureRef = sigFactory.newReference(
        "", 
        sigFactory.newDigestMethod(DigestMethod.SHA256, null),
        Collections.singletonList(sigFactory.newTransform(Transform.ENVELOPED, (XMLStructure) null)),
        null, 
        null
);

// 创建签名信息(指定规范化方法和签名算法)
SignedInfo signedInfo = sigFactory.newSignedInfo(
        sigFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (XMLStructure) null),
        sigFactory.newSignatureMethod(SignatureMethod.RSA_SHA256, null),
        Collections.singletonList(signatureRef)
);

// 准备密钥信息(把证书包含在签名里,方便服务端验证)
KeyInfoFactory keyInfoFactory = sigFactory.getKeyInfoFactory();
X509Data x509Data = keyInfoFactory.newX509Data(Collections.singletonList(cert));
KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));

// 创建签名对象
XMLSignature signature = sigFactory.newXMLSignature(signedInfo, keyInfo);

// 在SOAP Header中添加wsse:Security节点
SOAPEnvelope envelope = ((SOAPDocument) doc).getSOAPPart().getEnvelope();
SOAPHeader header = envelope.getHeader();
if (header == null) {
    header = envelope.addHeader();
}
Element securityElement = doc.createElementNS(
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", 
        "wsse:Security"
);
header.appendChild(securityElement);

// 执行签名,把签名结果写入securityElement节点
DOMSignContext signContext = new DOMSignContext(privateKey, securityElement);
signature.sign(signContext);

第四步:发送签名后的SOAP请求

把签名后的DOM文档转换成字节流,通过HTTP发送给服务端:

// 把DOM文档转换成字节流
Transformer transformer = TransformerFactory.newInstance().newTransformer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
transformer.transform(new DOMSource(doc), new StreamResult(baos));
byte[] signedSoapBytes = baos.toByteArray();

// 发送请求
URL serviceUrl = new URL("你的WebService地址");
HttpURLConnection conn = (HttpURLConnection) serviceUrl.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
conn.setDoOutput(true);

try (OutputStream os = conn.getOutputStream()) {
    os.write(signedSoapBytes);
    os.flush();
}

// 处理服务端响应...
int responseCode = conn.getResponseCode();
// 读取响应内容...

常见踩坑点排查

  • 命名空间错误:wsse:Security的命名空间必须和服务端要求完全一致,这是最容易导致签名验证失败的原因之一。
  • 算法不匹配:确认服务端要求的摘要算法(比如SHA256)和签名算法(比如RSA_SHA256),不要用过时的SHA1。
  • 签名位置错误:WS-Security签名必须放在SOAP Header的wsse:Security节点内,不能随意插入其他位置。
  • 密钥加载失败:检查密钥库路径、密码、别名是否正确,确保私钥能正常从密钥库中取出。

内容的提问来源于stack exchange,提问作者Otávio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:25:26