Spring WS SOAP请求Header添加ValueType属性失败求助
问题:Spring SOAP客户端无法添加BinarySecurityToken的ValueType属性
服务端要求的SOAP请求示例
<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:BinarySecurityToken xmlns:wsst="http://www.ibm.com/websphere/appserver/tokentype/5.0.2" ValueType="wsst:LTPA">generated_token</wsse:BinarySecurityToken> </wsse:Security> </soapenv:Header> <soapenv:Body> ... </soapenv:Body> </soapenv:Envelope>
实现的回调类代码
@Component public class CrmBinarySecurityTokenHeaderCallback implements WebServiceMessageCallback { @Autowired private TokenGenerator tokenGenerator; @Override public void doWithMessage(WebServiceMessage webServiceMessage) throws IOException, TransformerException { String securityToken = tokenGenerator.getToken(); try { SaajSoapMessage saajSoapMessage = (SaajSoapMessage) webServiceMessage; SOAPMessage soapMessage = saajSoapMessage.getSaajMessage(); SOAPPart soapPart = soapMessage.getSOAPPart(); SOAPEnvelope soapEnvelope = soapPart.getEnvelope(); SOAPHeader soapHeader = soapEnvelope.getHeader(); Name headerElementName = soapEnvelope.createName("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(headerElementName); SOAPElement securityTokenSoapElement = soapHeaderElement.addChildElement("BinarySecurityToken", "wsse"); securityTokenSoapElement.addNamespaceDeclaration("wsst", "http://www.ibm.com/websphere/appserver/tokentype/5.0.2"); QName valueType = securityTokenSoapElement.createQName("ValueType", "wsst"); securityTokenSoapElement.addAttribute(valueType, "LTPA"); securityTokenSoapElement.addTextNode(securityToken); soapMessage.saveChanges(); } catch (SOAPException e) { throw new RuntimeException(e); } } }
当前生成的SOAP请求(缺少ValueType属性)
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:BinarySecurityToken xmlns:wsst="http://www.ibm.com/websphere/appserver/tokentype/5.0.2"> generated_token </wsse:BinarySecurityToken> </wsse:Security> </SOAP-ENV:Header> <SOAP-ENV:Body> ... </SOAP-ENV:Body> </SOAP-ENV:Envelope>
问题说明
当前生成的请求与服务端要求几乎一致,但<wsse:BinarySecurityToken>元素始终无法添加ValueType="wsst:LTPA"属性,尝试使用SOAPElement.addAttribute()方法无效,求解决思路。
解决方法
问题核心是ValueType属性的命名空间归属错误:
- 在WS-Security规范中,
ValueType是BinarySecurityToken的标准属性,属于wsse命名空间,而非wsst。之前的代码错误地将属性归到wsst命名空间下,导致SOAP引擎未正确渲染该属性。 - 属性值
wsst:LTPA中的wsst是引用已声明的令牌类型命名空间,和属性本身的命名空间无关。
修改后的关键代码
替换原有的属性添加代码为:
// 使用wsse命名空间创建ValueType的QName QName valueType = soapEnvelope.createQName("ValueType", "wsse"); // 属性值为wsst:LTPA,引用已声明的wsst命名空间 securityTokenSoapElement.addAttribute(valueType, "wsst:LTPA");
完整修改后的回调类
@Component public class CrmBinarySecurityTokenHeaderCallback implements WebServiceMessageCallback { @Autowired private TokenGenerator tokenGenerator; @Override public void doWithMessage(WebServiceMessage webServiceMessage) throws IOException, TransformerException { String securityToken = tokenGenerator.getToken(); try { SaajSoapMessage saajSoapMessage = (SaajSoapMessage) webServiceMessage; SOAPMessage soapMessage = saajSoapMessage.getSaajMessage(); SOAPPart soapPart = soapMessage.getSOAPPart(); SOAPEnvelope soapEnvelope = soapPart.getEnvelope(); SOAPHeader soapHeader = soapEnvelope.getHeader(); Name headerElementName = soapEnvelope.createName("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(headerElementName); SOAPElement securityTokenSoapElement = soapHeaderElement.addChildElement("BinarySecurityToken", "wsse"); securityTokenSoapElement.addNamespaceDeclaration("wsst", "http://www.ibm.com/websphere/appserver/tokentype/5.0.2"); // 修正ValueType属性的命名空间 QName valueType = soapEnvelope.createQName("ValueType", "wsse"); securityTokenSoapElement.addAttribute(valueType, "wsst:LTPA"); securityTokenSoapElement.addTextNode(securityToken); soapMessage.saveChanges(); } catch (SOAPException e) { throw new RuntimeException(e); } } }
修改后重新生成的请求将包含正确的ValueType="wsst:LTPA"属性,符合服务端要求。
内容的提问来源于stack exchange,提问作者Alvaro Pedraza
相关产品推荐
相关产品推荐

