【问题标题】:Getting content of a SOAP Header using Spring WS使用 Spring WS 获取 SOAP Header 的内容
【发布时间】:2016-02-15 14:34:59
【问题描述】:

我正在尝试构建一个将从客户端接收 SOAP 消息的端点。我收到的消息在soap标头中包含用户名和密码...

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://www.company.com/Application">
    <soapenv:Header  xmlns:wsse="http://__________.xsd">
        <wsse:Security >
            <wsse:UsernameToken>
                <wsse:Username>username</wsse:Username>
                <wsse:Password>password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>

   </soapenv:Header>
   <soapenv:Body>

我正在使用 Spring WS - 显而易见的解决方案是在 web.xml 中创建一个过滤器,它将完全绕过 Spring WS,解析 SOAP 消息,提取用户名和密码,然后继续使用 Spring WS,它将解析 SOAP再次。

有没有办法在不绕过 Spring WS 的情况下获取 header 的内容?

我尝试在 sws:interceptors 中添加一个 bean:

<sws:interceptors>

    <!-- extract Security details from Header -->
    <bean class="com.company.application.service.SecurityInterceptorService" />

    <!-- log full Body of request -->
    <bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>

    <!-- validate Request against XSD to make sure it's a valid request -->
    <bean id="CompanyApplication" class="com.company.application.interceptor.ValidatingInterceptor">
        <property name="schema" value="/WEB-INF/_______________.xsd" />
        <property name="validateRequest" value="true" />
        <property name="validateResponse" value="true" />
    </bean>

</sws:interceptors>

然后实现那个类:

public class SecurityInterceptorService implements EndpointInterceptor {


    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {

        System.out.println("---------------");
        System.out.println("handleRequest")                                             ;
        System.out.println("---------------");


        return true;
    }

    @Override
    public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {

        System.out.println("---------------");
        System.out.println("handleResponse");
        System.out.println("---------------");



        return true;
    }

    @Override
    public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {

        System.out.println("---------------");
        System.out.println("handleFault");
        System.out.println("---------------");


        return true;
    }

    @Override
    public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {

        System.out.println("---------------");
        System.out.println("afterCompletion");
        System.out.println("---------------");

    }



}

endpoint 仅包含有关handleRequest 内部端点的数据,并且在调试模式下遍历messageContext 内部的许多层和层之后,我似乎无法发现标头的内容。

我在 messageContext 中寻找的内容是否存在,如果是,我如何访问它?

【问题讨论】:

标签: java spring web-services soap spring-ws


【解决方案1】:

messageContext 对象,您可以检索请求或响应(在您的情况下,我猜您需要请求)。

请求/响应基本上是WebServiceMessage。如果您检查 webServiceMessage,您将看到该对象可以转换为 SoapMessage。从soap 消息中,您现在可以获取soap 标头。

WebServiceMessage webServiceMessageRequest = messageContext_.getRequest();
SoapMessage soapMessage = (SoapMessage) webServiceMessageRequest;
SoapHeader soapHeader = soapMessage.getSoapHeader()

之后,您可能希望获取source 对象并将其转换为DOMSource 对象,然后获取Node 对象,这使得信息检索更加容易。

Source bodySource = soapHeader .getSource();
DOMSource bodyDomSource = (DOMSource) bodySource;
Node bodyNode = _bodyDomSource.getNode();

【讨论】:

  • 这很有道理,谢谢@VirtualTroll!不知道我必须做一些选角才能获得正确的东西。
【解决方案2】:

如果你使用的是spring-boot,你可以使用这种配置:

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {

  @Override
  public void addInterceptors(List<EndpointInterceptor> interceptors) {
    PayloadValidatingInterceptor validatingInterceptor = new PayloadValidatingInterceptor();
    validatingInterceptor.setValidateRequest(true);
    validatingInterceptor.setValidateResponse(true);
    validatingInterceptor.setXsdSchema(resourceSchema());
    interceptors.add(validatingInterceptor);
  }

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

  @Bean(name = "registros")
  public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
    DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
    wsdl11Definition.setPortTypeName("ResourcePort");
    wsdl11Definition.setLocationUri("/api");
    wsdl11Definition.setTargetNamespace("http://resource.com/schema");
    wsdl11Definition.setSchema(resourceSchema());
    return wsdl11Definition;
  }

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

在本例中,addInterceptors 方法是重要的,其他 3 个是公开 WSDL API 的基本方法。

也许它对其他人有用。

【讨论】:

  • 这里的 PayloadValidatingInterceptor 是什么?
  • 这是一个拦截器,其目的是验证请求是否满足架构定义
【解决方案3】:

没有简单的方法可以用 Spring-ws 解组 Soap 标头 (it's currently not supported) 但是,您可以在 @PayloadRoot 注释方法中访问 SoapHeaderElement,并使用 JAXB 执行解组过程。

@Endpoint
public class SubmitEndpoint implements EndpointInterface {

    private static final String NAMESPACE_URI = "http://www.example.com/namespace";

    private Security unmarshallSecurityFromSoapHeader(SoapHeaderElement header) {
        Security security = null;
        try {

            JAXBContext context = JAXBContext.newInstance(Security.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            security = (Security) unmarshaller.unmarshal(header.getSource());

        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return security;
    }

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "submit")
    @ResponsePayload
    public SubmitResponse submit(@RequestPayload Submit submit, @SoapHeader(
            value = "{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security") SoapHeaderElement wsseSecurityHeader) throws JAXBException {


        Security security = unmarshallSecurityFromSoapHeader(wsseSecurityHeader);

    }
}

Security.java

@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(namespace = Security.SECURITY_NS, name = "Security")
public class Security {

    public static final String SECURITY_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";

    @XmlElement(namespace = SECURITY_NS, name = "UsernameToken")
    private UsernameToken usernameToken;

}

UsernameToken.java

@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(namespace = Security.SECURITY_NS, name = "UsernameToken")
public class UsernameToken {

    @XmlElement(name = "Username", namespace = Security.SECURITY_NS)
    private String username;

    @XmlElement(name = "Password", namespace = Security.SECURITY_NS)
    private String password;

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    相关资源
    最近更新 更多