本篇博文使用3种不同的方法,在Spring SOAP(Simple Object Access Protocol)上添加自定义头信息。头信息一般是服务端用于身份验证的。
SOAP头信息在SWDL文档中是不会提及的,这需要程序员手动在请求上添加头信息。这里可以使用interceptor用于添加头信息,也可以在WebServiceMessageCallback中重写dowithMessage()方法上做,也可以在JAXB Marshaller中添加头信息。
下面是一个简单的SOAP请求的XML头信息。
- <soapenv:Header>
- <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
- <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
- <wsse:Username>abcwsse:Username>
- <wsse:Password>abcwsse:Password>
- wsse:UsernameToken>
- wsse:Security>
- soapenv:Header>
在添加头信息前,首先要有一个SOAP的适配器,如下代码:
BlzServiceAdpter.java
- public class BlzServiceAdapter extends WebServiceGatewaySupport {
-
- private static final Logger logger = LoggerFactory.getLogger(BlzServiceAdapter.class);
-
- public GetBankResponseType getBank(String url, Object requestPayload){
- WebServiceTemplate webServiceTemplate = getWebServiceTemplate();
- JAXBElement res = null;
- try {
- res = (JAXBElement) webServiceTemplate.marshalSendAndReceive(url, requestPayload);
- }catch(SoapFaultClientException ex){
- logger.error(ex.getMessage());
- }
- return res.getValue();
- }
- }
首先在application.properties文件中添加对应的头数据,和用户名密码
- soap.auth.header=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%(loginuser) "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">%(loginpass) - soap.auth.username=testuser
- soap.auth.password=testpass
然后getBank中读取application.properties中关于soap头的信息,并将头信息设置到webServiceTemplate中
- private static final Logger logger = LoggerFactory.getLogger(BlzServiceAdapter.class);
-
- @Autowired
- private Environment environment;
-
- public GetBankResponseType getBank(String url, Object requestPayload){
- WebServiceTemplate webServiceTemplate = getWebServiceTemplate();
- JAXBElement res = null;
- try {
- res = (JAXBElement) webServiceTemplate.marshalSendAndReceive(url, requestPayload, new WebServiceMessageCallback() {
-
- @Override
- public void doWithMessage(WebServiceMessage message) {
- try {
- SoapHeader soapHeader = ((SoapMessage) message).getSoapHeader();
- Map mapRequest = new HashMap();
-
- mapRequest.put("loginuser", environment.getProperty("soap.auth.username"));
- mapRequest.put("loginpass", environment.getProperty("soap.auth.password"));
- StringSubstitutor substitutor = new StringSubstitutor(mapRequest, "%(", ")");
- String finalXMLRequest = substitutor.replace(environment.getProperty("soap.auth.header"));
- StringSource headerSource = new StringSource(finalXMLRequest);
- Transformer transformer = TransformerFactory.newInstance().newTransformer();
- transformer.transform(headerSource, soapHeader.getResult());
- logger.info("Marshalling of SOAP header success.");
- } catch (Exception e) {
- logger.error("error during marshalling of the SOAP headers", e);
- }
- }
- });
- }catch (SoapFaultClientException e){
- logger.error("Error while invoking session service : " + e.getMessage());
- return null;
- }
- return res.getValue();
- }
这里有一点要注意,如果要在header中的security结点上添加一个新的结点,这个方式就会报错The markup in the document following the root element must be well-formed,解决办法是手动加一个SOAPHeaderElement在头信息中。
在doWithMessage()函数中实现,首先手动创建SOAPHeaderElement及SOAPElement,然后再把这个添加到SOAPHeader上。
TokenHeaderRequestCallbak.java
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.ws.WebServiceMessage;
- import org.springframework.ws.client.core.WebServiceMessageCallback;
- import org.springframework.ws.soap.saaj.SaajSoapMessage;
-
- import javax.xml.soap.*;
-
- public class TokenHeaderRequestCallback implements WebServiceMessageCallback {
-
- private static final Logger logger = LoggerFactory.getLogger(SessionHeaderRequestCallback.class);
-
- private String username;
- private String password;
-
- public TokenHeaderRequestCallback(String username, String password){
- this.username = username;
- this.password = password;
- }
-
- public void doWithMessage(WebServiceMessage message) {
-
- try {
-
- SaajSoapMessage saajSoapMessage = (SaajSoapMessage)message;
-
- 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 usernameTokenSOAPElement = soapHeaderElement.addChildElement("UsernameToken", "wsse");
-
- SOAPElement userNameSOAPElement = usernameTokenSOAPElement.addChildElement("Username", "wsse");
- logger.info(this.username);
- userNameSOAPElement.addTextNode(this.username);
-
- SOAPElement passwordSOAPElement = usernameTokenSOAPElement.addChildElement("Password", "wsse");
-
- passwordSOAPElement.addTextNode(this.password);
-
- soapMessage.saveChanges();
- } catch (SOAPException soapException) {
- throw new RuntimeException("TokenHeaderRequestCallback", soapException);
- }
- }
- }
这种方式比较简单,在JAXB marshaller上创建SOAP header就可以了。如下代码:
- @Override
- public void doWithMessage(WebServiceMessage message) {
- try {
- SoapHeader soapHeader = ((SoapMessage) message).getSoapHeader();
- ObjectFactory factory = new ObjectFactory();
- AuthSoapHeaders authSoapHeaders =
- factory.createAuthSoapHeaders();
- authSoapHeaders.setUsername("testuser");
- authSoapHeaders.setPassword("testpass");
- JAXBElement headers =
- factory.createAuthSoapHeaders(AuthSoapHeaders);
- JAXBContext context = JAXBContext.newInstance(AuthSoapHeaders.class);
- Marshaller marshaller = context.createMarshaller();
- marshaller.marshal(authSoapHeaders, soapHeader.getResult());
- } catch (Exception e) {
- logger.error("error during marshalling of the SOAP headers", e);
- }
- }
- });