简体   繁体   中英

How to add soap header when making a soap request using the java objects generated by wsdl

I generated client java objects using JAX-WS RI. I am trying to make a SOAP request to a web service. Service requires authentication in the header which looks like below:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<xsd:authHeader>
<xsd:user>username@gmail.com</xsd:user>
<xsd:password>password1</xsd:password>
</xsd:authHeader>
</soapenv:Header>
<soapenv:Body>
<ns:searchAssetsParam>
<ns:includeSubfolders>true</ns:includeSubfolders>
<ns:resultsPage>2</ns:resultsPage>
</ns:searchAssetsParam>
</soapenv:Body>
</soapenv:Envelope>

The generated java objects have methods for calling the service, creating the objects and constructing the header. But, I am having trouble setting the header while making the call.

Here's the code that I am using:

IpsApiService service = new IpsApiService();
IpsApiPortType port = service.getIpsApiSoapPort();
SearchAssetsParam searchAssetsParam = buildSearchAssetsParam();
SearchAssetsReturn response = port.searchAssets(searchAssetsParam);

buildSearchAssetsParam() constructs the request object. I created the header object as follows:

AuthHeader header = new AuthHeader();
header.setUser("username@gmail.com");
header.setPassword("password1");

How do I set this AuthHeader to the service request?

Thanks, Venu

Once I had the same problem. I needed to modify the JAX-WS web service SOAP header at every request. To solve this problem I have created a handler like this:

public class MyHandler implements SOAPHandler<SOAPMessageContext> {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class);

    private String username;

    private String password;

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        try {
            SOAPMessage message = context.getMessage();
            SOAPHeader header = message.getSOAPHeader();
            SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
            if (header == null) {
                header = envelope.addHeader();
            }
            QName qNameUserCredentials = new QName("https://your.target.namespace/", "UserCredentials");
            SOAPHeaderElement userCredentials = header.addHeaderElement(qNameUserCredentials);

            QName qNameUsername = new QName("https://your.target.namespace/", "Username");
            SOAPHeaderElement username = header.addHeaderElement(qNameUsername );
            username.addTextNode(this.username);
            QName qNamePassword = new QName("https://your.target.namespace/", "Password");
            SOAPHeaderElement password = header.addHeaderElement(qNamePassword);
            password.addTextNode(this.password);

            userCredentials.addChildElement(username);
            userCredentials.addChildElement(password);

            message.saveChanges();
            //TODO: remove this writer when the testing is finished
            StringWriter writer = new StringWriter();
            message.writeTo(new StringOutputStream(writer));
            LOGGER.debug("SOAP message: \n" + writer.toString());
        } catch (SOAPException e) {
            LOGGER.error("Error occurred while adding credentials to SOAP header.", e);
        } catch (IOException e) {
            LOGGER.error("Error occurred while writing message to output stream.", e);
        }
        return true;
    }

    //TODO: remove this class after testing is finished
    private static class StringOutputStream extends OutputStream {

        private StringWriter writer;

        public StringOutputStream(StringWriter writer) {
            this.writer = writer;
        }

        @Override
        public void write(int b) throws IOException {
            writer.write(b);
        }
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        LOGGER.debug("handleFault has been invoked.");
        return true;
    }

    @Override
    public void close(MessageContext context) {
        LOGGER.debug("close has been invoked.");
    }

    @Override
    public Set<QName> getHeaders() {
        LOGGER.debug("getHeaders has been invoked.");
        return null;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

It adds the needed parameters to my SOAP header and it is invoked on every request. All you need to do is to modify handleMessage method to suit your needs.

It works for me by overriding the public void setAttribute(String namespace, String localName, String value) method.

import javax.xml.namespace.QName;
import org.apache.axis.Constants;
import org.apache.axis.message.SOAPHeaderElement;

@SuppressWarnings("serial")
public class ADESHeaderElement  extends SOAPHeaderElement 
{

     public ADESHeaderElement(QName qname, Object value)
        {
            super(qname, value);
        }

     @Override
     public void setAttribute(String namespace, String localName, String value) 
     {
       if (!Constants.ATTR_MUST_UNDERSTAND.equals(localName)) 
       {  // Or any other attribute name you'd want to avoid
         super.setAttribute(namespace, localName, value);
       }
     }
}

Create header element like this:

 ADESHeaderElement custheader = new ADESHeaderElement(qname, clientserv);          
        custheader.setActor(null);

When you create your service from classess generated by cxf, add custom interceptor

Service service = new MyService(wsdlURL, new QName("http://myservice.com/MyService/", "MyService"));
MyPort port = service.getMyPort();
Client client = ClientProxy.getClient(port);
// adding interceptor programmatically
client.getOutInterceptors().add(new MyHeaderHandler());

Your can extend AbstractSoapInterceptor to implement your custom interceptor to handle message.

import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;

import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.phase.Phase;

import com.rpc.core.utils.DomainContext;

public class MyHeaderHandler extends AbstractSoapInterceptor {

    /**
    * Constructor
    */
    public MyHeaderHandler() {
        super(Phase.PRE_LOGICAL);

    }

    @Override
    public void handleMessage(org.apache.cxf.binding.soap.SoapMessage message) throws org.apache.cxf.interceptor.Fault {
        try {
            message.getHeaders().add(new Header(new QName("MyCustomHeader"),"value", new JAXBDataBinding(String.class)));
             } catch (JAXBException e) {
                 e.printStackTrace();
             }
         };
     }
}

Yes, I did the same that Rangappa Tungal, following this example:

Service w = new ServiceLocator();  
ServiceSoap ws = new ServiceSoapStub(new URL(w.getServiceSoapAddress()),w); Stub mystub = (Stub) ws;
AuthHeader up = new AuthHeader("user","pass");
mystub.setHeader("namespace", "AuthHeader", up);
ws.get***();

Link to the example!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM