Spring 引导 - 如何将自定义 headers 添加到 SOAP 响应?

Spring Boot - How add custom headers to SOAP Response?

我目前有以下端点,我的目的是将自定义 header 添加到默认情况下始终为空的当前响应 header。

目前我有以下 classes/configurations:

@Endpoint
public class AddressEndPoint extends WebServiceGatewaySupport {

  @Autowired
  private AddressService addressService;

  @Autowired
  private ConfigProperties configProperties;

  @PayloadRoot(namespace = "http://www.swisscom.com/wsg/bb/v42", localPart = "getAddressRequest")
  @ResponsePayload
  public GetAddressResponse getAddressRequest(@RequestPayload GetAddressRequest request)
    throws DatatypeConfigurationException
  {
    UUID uuid = UUID.randomUUID();
    GetAddressResponse response = new GetAddressResponse();
    response.setAddress(addressService.getAddress(request.getCity())); //Get the city from AddressService method by passing as parameter the city of the request obj
    response.setDnType(DnType.BBCS_QUALIFY.getType());
    response.setBasisContrEleId(BasisContrEleId.BBCS_BASISCONTR.getType());
    response.setBbType(BbType.BBCS_BBTYPE.getType());
    response.setContrEleId(ContrEleId.BBCS_CONTRELE.getType());
    response.setIspId(Integer.parseInt(configProperties.getConfigValue("ispId")));
    response.setQualifExtRef(uuid.toString());
    response.setReturnSpeedAtNok(Boolean.TRUE);
    response.setSfSlaId(SetSfSlaId.FIRST_POSSIBLE.getType());
    GregorianCalendar gcal = new GregorianCalendar();
    XMLGregorianCalendar xgcal = DatatypeFactory.newInstance()
                .newXMLGregorianCalendar(gcal);
    response.setCustomerWishDate(xgcal);
    //GetAddressResponse testResponse = getWebServiceTemplate().marshalSendAndReceive((GetAddressResponse) response, new SoapRequestHeaderModifier());
    //return (GetAddressResponse) getWebServiceTemplate().marshalSendAndReceive(response, new SoapRequestHeaderModifier());
    return response;
  }
}

以及以下 SOAP 配置:

@EnableWs
@Configuration
public class SoapWebServiceConfig extends WsConfigurerAdapter {

  //Add this in package-info.java
  /*xmlns = {
        @XmlNs(prefix = "v42", namespaceURI="http:xxxxxxxx.com/xx/xx/v42")
        },*/

  @Bean
  public ServletRegistrationBean messageDispatcherServlet(ApplicationContext context){
    MessageDispatcherServlet servlet = new MessageDispatcherServlet();
    servlet.setApplicationContext(context);
    servlet.setTransformWsdlLocations(true);
    return new ServletRegistrationBean(servlet, "/soapWS/*");
  }

  //Added for WS Security
  @Bean
  public Jaxb2Marshaller marshaller() {
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setContextPath("com.swisscom.wsg.bb.v42");
    return marshaller;
  }

  @Bean
  public XsdSchema userSchema() {
    return new SimpleXsdSchema(new ClassPathResource("users.xsd"));
  }

  @Bean
  public XsdSchema addressSchema(){
    return new SimpleXsdSchema(new ClassPathResource("address.xsd"));
  }

  @Bean
  public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema userSchema){
    DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
    definition.setSchema(userSchema);
    definition.setLocationUri("/soapWS");
    definition.setPortTypeName("UserServicePort");
    definition.setTargetNamespace("http://www.swisscom.com/wsg/bb/v42");
    return definition;
  }
}

我的意图是在 Security 下的响应 header 中添加一个 usernameToken 元素,其中包含 usernamepassword.

示例:

<wsse:Security soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
   <wsse:UsernameToken>
      <wsse:Username>xxxx</wsse:Username>
      <wsse:Password>xxxxx</wsse:Password>
   </wsse:UsernameToken>
</wsse:Security>

我已经尝试了一些示例,正如您从我的注释代码中看到的那样,但没有成功。

如有任何帮助,我们将不胜感激。

我设法通过以下方式解决了我的问题:

private static final String TARGET_NAMESPACE = "http://www.swisscom.com/wsg/bb/v42";

    @PayloadRoot(namespace = "http://www.swisscom.com/wsg/bb/v42", localPart = "getAddressRequest")
    @ResponsePayload
    public GetAddressResponse getAddressRequest(@RequestPayload GetAddressRequest request, MessageContext messageContext) throws DatatypeConfigurationException, JAXBException {

        //Create Response Body and Header
        SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
        SoapHeader soapResponseHeader = soapResponse.getSoapHeader();

        //New UsernameHeader Object
        UsernameHeader usernameToken = new UsernameHeader();

        //Set UsernameHeader Object values
        usernameToken.setUsername("SandyAPI");
        usernameToken.setPassword("Test_Password");

        //Create SecurityHeader Object that will contain the UsernameHeader Object
        SecurityHeader securityHeader = new SecurityHeader();
        securityHeader.setUsernameHeader(usernameToken);

        //Genetare random UUID
        UUID uuid = UUID.randomUUID();

        //Create new GetAddressResponse Object and set the values (body)
        GetAddressResponse response = new GetAddressResponse();
        response.setAddress(addressService.getAddress(request.getCity())); //Get the city from AddressService method by passing as parameter the city of the request obj
        response.setDnType(DnType.BBCS_QUALIFY.getType());
        response.setBasisContrEleId(BasisContrEleId.BBCS_BASISCONTR.getType());
        response.setBbType(BbType.BBCS_BBTYPE.getType());
        response.setContrEleId(ContrEleId.BBCS_CONTRELE.getType());
        response.setIspId(Integer.parseInt(configProperties.getConfigValue("ispId")));
        response.setQualifExtRef(uuid.toString());
        response.setReturnSpeedAtNok(Boolean.TRUE);
        response.setSfSlaId(SetSfSlaId.FIRST_POSSIBLE.getType());
        GregorianCalendar gcal = new GregorianCalendar();
        XMLGregorianCalendar xgcal = DatatypeFactory.newInstance()
                .newXMLGregorianCalendar(gcal);
        response.setCustomerWishDate(xgcal);


        //Send Response back (Classes marshalled)
        JAXBContext jaxbContext = JAXBContext.newInstance(SecurityHeader.class);
        jaxbContext.createMarshaller().marshal(securityHeader, soapResponseHeader.getResult());

        return response;

    }

输出:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header>
        <wsse:Security>
            <wsse:UsernameToken>
                <wsse:Username>SandyAPI</wsse:Username>
                <wsse:Password>Test_Password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
        <v42:getAddressResponse xmlns:v42="http://www.swisscom.com/wsg/bb/v42">
            <v42:ispId>100032</v42:ispId>
            <v42:basisContrEleId>120</v42:basisContrEleId>
            <v42:contrEleId>100</v42:contrEleId>
            <v42:bbType>2</v42:bbType>
            <v42:dnType>1</v42:dnType>
            <v42:address>
                <v42:city>Bellinzona</v42:city>
                <v42:street>Viale Stazione</v42:street>
                <v42:house>33</v42:house>
                <v42:zip>6500</v42:zip>
            </v42:address>
            <v42:qualifExtRef>a390c3a4-2810-4b49-a48a-6c9de98beab1</v42:qualifExtRef>
            <v42:returnSpeedAtNok>true</v42:returnSpeedAtNok>
            <v42:sfSlaId>1</v42:sfSlaId>
            <v42:customerWishDate>2019-11-26+01:00</v42:customerWishDate>
        </v42:getAddressResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>