background

Recently, I have done a docking work to connect with an old system, using WebService technology. Because the industry users are in has high requirements for security and the system construction takes a long time, there are still many WebService docking methods. However, the second level is different from the previous ones. There are strict restrictions on interface naming, and authentication information should be added to the TRANSMITTED XML data. This means that the server parses and authenticates the custom data structure. The client manually assembles the account information into XML.

The solution

Technical framework

The reason for this is that a lot of the information we have found is that the practical CXF framework implements this requirement, and we use spring-boot-starter-web-services. So far, I really haven’t found a complete solution, so I will record it here. In addition, I see some people are directly assembled to return the string, in this worship of perseverance, but this is very not advocated, too difficult to maintain.

XSD defines

The service side

AuthInterceptor.java

public class AuthInterceptor extends EndpointInterceptorAdapter {
   
    @Value("${userName:name}")
    private String serverUserName;
    @Value("${userPassword:psw}")
    private String serverPassoword;

    @Override
    public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
        SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
        SOAPMessage soapMessage = soapResponse.getSaajMessage();
        SOAPBody body = null;
        try {
            body = soapMessage.getSOAPBody();
           
            
            NodeList chlidrenNodes = body.getChildNodes();
            for (int i = 0; i < chlidrenNodes.getLength(); i++) {
                Node node = chlidrenNodes.item(i);
                node.setPrefix(systemShortName);
                NodeList subNodes = node.getChildNodes();
                for (int j = 0; j < subNodes.getLength(); j++) {
                    Node subNode = subNodes.item(j);
                    subNode.setPrefix(systemShortName);
                }
    
            }
            
            Iterator<SOAPElement> iterator=body.getChildElements();
            while(iterator.hasNext()){
                SOAPElement element=iterator.next();
                // You can customize your own space here. The default space in ps is N2
                 element.removeNamespaceDeclaration("ns2"); }}catch (SOAPException e) {
            log.error("getSOAPbody error:{}", e.getMessage(), e);
        }
        soapMessage.saveChanges();
        return super.handleRequest(messageContext, endpoint);
    }

    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
        SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext.getRequest();
        SOAPMessage soapMessage = soapRequest.getSaajMessage();
        SOAPHeader header = null;
        try {
            header = soapMessage.getSOAPHeader();
        } catch (SOAPException e) {
            log.error("getSOAPheader error:{}", e.getMessage(), e);
        }   
        NodeList chlidrenNodes = securityNode.item(0).getChildNodes();
        String userName = "";
        String password = "";
        for (int i = 0; i < chlidrenNodes.getLength(); i++) {
            Node node = chlidrenNodes.item(i);
            if (node.getNodeName().contains("username")) {
                userName = node.getTextContent().trim();

            }
            if (node.getNodeName().contains("password")) { password = node.getTextContent().trim(); }}if (serverUserName.equals(userName) && serverPassword.equals(password)) {
            log.debug("admin auth success");
        } else {
            SOAPException soapException = new SOAPException("Authentication error");
            log.debug("admin auth failed");
            throw new Exception(soapException);
        }
        soapMessage.saveChanges();
        return super.handleRequest(messageContext, endpoint); }}Copy the code

WsServiceConfig.java

@EnableWs
@Configuration
public class WsServiceConfig extends WsConfigurerAdapter {
    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    @Bean(name = "endpoint")
    public DefaultWsdl11Definition defaultWsdl11DefinitionData(XsdSchema updateSchema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
       // It depends on the business
        wsdl11Definition.setSchema(updateSchema);
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema updateSchema(a) {
        return new SimpleXsdSchema(new ClassPathResource("xx.xsd"));
    }
    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        // Custom authentication interceptor
        interceptors.add(authInterceptor());
    }
    @Bean
    public AuthInterceptor authInterceptor(a){
        return newAuthInterceptor(); }}Copy the code

The client

WsAuthInterceptor.java

@Slf4j
@Component
public class WsAuthInterceptor extends ClientInterceptorAdapter{
    private static final String SECURITY_NODE_NAME="security";
    @Value("${username:username}")
    private  String username;
    @Value("${password:password}")
    private String password;

    @Override
    public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
        SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext.getRequest();
        SOAPMessage soapMessage = soapRequest.getSaajMessage();
        SOAPHeader header = null;
        try {
            header = soapMessage.getSOAPHeader();
            SOAPElement secrity=header.addChildElement(SECURITY_NODE_NAME);
            //xx is the namespace
            SOAPElement nameElement=secrity.addChildElement("username"."xx");
            SOAPElement passwordElement=secrity.addChildElement("password"."xx");
            nameElement.setValue(systemStortName);
            passwordElement.setValue(SM3EncryptUtil.encrypt(costumerPassword));
            soapMessage.saveChanges();
        } catch (SOAPException e) {
            log.error("getSOAPheader error:{}", e.getMessage(), e);
        }
        
        return super.handleRequest(messageContext); }}Copy the code

When used this way,client is an instance of extend WebServiceGatewaySupport.

  ClientInterceptor[] interceptors=new ClientInterceptor[]{customIterceptor};
        client.setInterceptors(interceptors);
Copy the code

conclusion

Professional pit filling.