Spring WS client set cookie for authentication

帅比萌擦擦* 提交于 2020-01-25 18:40:10

问题


In order to consume a RPC web service, first I have to call a web method 'Authentication' and then I am supposed to be able to call other web methods. I have tried to implement a spring web client to consume this service but something is going terribly wrong.

This service was originally designed for php users and the sample client code they provided is as following:

$soap = new SoapClient('http://www.2972.ir/wsdl?XML'); 
if ($soap->Authentication('user', '123456')) { 
    echo $soap->getCredit();
}

'authentication' method will return 1 when successful and -1 otherwise. 'getCredit' method return a float showing user current balance.

Now my implementation in Java:

@Service
public class MessageService implements IMessageService {

    @Autowired
    private IranSMSPanelPortType webService;

    public String doSomething() {
        int status = webService.authentication("user", "123456");
        System.out.println("# status: "+status);
        return String.valueOf(webService.getCredit());
    }

The status code I get is equal to '1' but upon calling the second web method I get this exception:

 javax.xml.ws.soap.SOAPFaultException: You are not authorized


It is clear that calling the 'authentication' method in php does not have the same effect as calling it in java. So I investigated a little more and found out that something is being set in the response cookies of 'authentication' web method.

Here is a glance at the response :

Headers

HTTP/1.1 200 OK
Date: Thu, 07 Aug 2014 17:26:49 GMT
Server: Apache/2
X-Powered-By: PHP/5.4.24
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Set-Cookie: PHPSESSID=m607671c9d8aeks5vm2r84n8r3; path=/
Vary: Accept-Encoding,User-Agent
Transfer-Encoding: chunked
Content-Type: text/xml; charset=utf-8

Envelope

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.iransmspanel.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:AuthenticationResponse>
      <result xsi:type="xsd:int">1</result>
    </ns1:AuthenticationResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


As you can see a PHPSESSID has been assigned a value! It is most likely that this parameter is used to handle the authorization.

Given the following Spring Web Service configuration how can I achieve the same result?

<bean id="smsWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
    <property name="serviceInterface" value="com.iransmspanel.IranSMSPanelPortType" />  
    <property name="wsdlDocumentUrl"  value="http://www.2972.ir/wsdl?XML" />
    <property name="namespaceUri"     value="http://www.iransmspanel.com/" />
    <property name="serviceName"      value="IranSMSPanel" />
    <property name="portName"         value="IranSMSPanelPort" />
</bean>


I would welcome other implementation of the web service client if it is necessary to handle the authentication.


回答1:


I finally managed to solve this problem using a custom SAOP-Handler and manually extracting PHPSESSID from message Http Headers.


Spring Configuration

<bean id="smsWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
    ...
    <property name="handlerResolver"  ref="credentialHandlerResolver"/>
</bean>

<bean id="credentialHandlerResolver" class="com.example.handlers.CredentialHandlerResolver"/>


CredentialHandlerResolver.java

import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
...

public class CredentialHandlerResolver implements HandlerResolver {
    private List<Handler> chain;
    CredentialHandlerResolver() {
        chain = new ArrayList<Handler>();
        chain.add(new CredentialHandler());
    }
    public List<Handler> getHandlerChain(PortInfo portInfo) {
        return chain;
    }
}


CredentialHandler.java

public class CredentialHandler implements SOAPHandler<SOAPMessageContext> {
    public static String PHPSESSID;

    public boolean handleMessage(SOAPMessageContext context) {
        Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        try {
            SOAPMessage message = context.getMessage();
            SOAPBody body = message.getSOAPPart().getEnvelope().getBody();
            if(!isRequest && body.getFirstChild().getLocalName().equals("AuthenticationResponse") && body.getFirstChild().getTextContent().equals("1")) {
                // extracting PHPSESSID from HTTP headers
                Map<String, List<String>> httpHeaders = (Map<String, List<String>>) context.get(MessageContext.HTTP_RESPONSE_HEADERS);
                String session = httpHeaders.get("Set-Cookie").get(0);
                PHPSESSID = session.substring(10, session.indexOf(';'));
            }
            else if (isRequest && PHPSESSID != null && !body.getFirstChild().getLocalName().equals("Authentication")){
                // add PHPSESSID to HTTP headers
                Map<String, List<String>> headers = new HashMap<String, List<String>>();
                headers.put("Cookie", Arrays.asList("PHPSESSID=" + PHPSESSID));
                context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
            }
        }
        catch (SOAPException ex) {
            ex.printStackTrace();
            return false;
        }
        return true;
    }


来源:https://stackoverflow.com/questions/25189129/spring-ws-client-set-cookie-for-authentication

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!