最近我們還需要使用SOAP服務來支持JSESSIONID,這就是我們在閱讀StackOverflow並引用IBM站點上的SSO客戶端示例後想出的。
我們擴展了SOAPHandler:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.List;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import com.sun.istack.internal.Nullable;
public class SoapMessageHandler implements SOAPHandler<SOAPMessageContext> {
private String sessionCookie = "";
@Override
public void close(MessageContext arg0) { }
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Set getHeaders() {
return null;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext) {
if ((Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
// Add header to outbound request (set cookie in HTTP client header)
// Set the Cookie
Map<String, List<String>> headers = (Map<String, List<String>>)soapMessageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
if (headers == null) {
headers = new HashMap<String, List<String>>();
soapMessageContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
List<String> cookie = headers.get("Cookie");
if (cookie == null) {
cookie = new ArrayList<String>();
headers.put("Cookie", cookie);
}
cookie.add(sessionCookie);
} else {
// Read header from request (read cookie from server's HTTP headers)
Map<String, List<String>> map = (Map<String, List<String>>) soapMessageContext.get(MessageContext.HTTP_RESPONSE_HEADERS);
List<String> contentType = getHTTPHeader(map, "Set-Cookie");
// Note, only grabs last cookie value!
// If you need to present more than one cookie you could make
// sessionCookie a List<String> and modify this class accordingly.
if (contentType != null) {
StringBuffer strBuf = new StringBuffer();
for (String type : contentType) {
strBuf.append(type);
}
sessionCookie = strBuf.toString();
}
}
return true;
}
private @Nullable List<String> getHTTPHeader(Map<String, List<String>> headers, String header) {
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
String name = entry.getKey();
if (header != null && name !=null) {
if (name.equalsIgnoreCase(header))
return entry.getValue();
}
}
return null;
}
}
這也需要HandlerResolver:
import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
public class SoapHandlerResolver implements HandlerResolver {
@SuppressWarnings("unchecked")
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(new SoapMessageHandler());
return handlerChain;
}
}
擴展HandlerResolver調用,像這樣的SOAP服務時,則調用:
ExampleService exampleService = new ExampleService();
exampleService.setHandlerResolver(new SoapHandlerResolver());
Example example = exampleService.getExampleServicePort();
example.myMethod();
對於我們來說,這對於Java 6來說是有效的,但僅限於支持一個Cookie標頭(儘管可以進行簡單修改以支持多個Cookie標頭)。
注意:如果像我們一樣,你必須通過多個服務之間的相同的會話cookie(好象在SOAP服務餅乾還不夠糟糕)而不是此:
private String sessionCookie = "";
你可以只做到這一點:
static private String sessionCookie = "";
這是超級哈克,並可能會或可能不是你根據服務(和你的代碼)是如何工作的,以及如何可以會話,你可以對遠程服務的工作,所以我建議比在生產中使用靜態更復雜的東西。
也許你的cookie被存儲在數據庫中的web服務的終端和服務器只給你一個會話ID的服務。順便說一下,你是否嘗試過一個自定義HTTP頭,比如「X-MyCustomHeader:my value」,而不是Cookie頭? –