Bil*_*l G 5 java web-services jax-ws
我正在尝试访问第三方Web服务,该服务要求我创建一个传递时间信息,用户名和密码的安全标头.我已经在网上搜索工作示例,并尝试了很多方法.我正试图用Java 6中内置的东西来做这件事.我不确定我做错了什么.从WSDL生成我的Web服务客户端类之后,我在下面创建了Handler.
import java.util.Set;
import java.util.TimeZone;
import javax.xml.namespace.QName;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.Text;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class MyHeaderHandler implements SOAPHandler<SOAPMessageContext>
{
public boolean handleMessage(SOAPMessageContext context)
{
String prefixUri = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-";
String uri = prefixUri + "wssecurity-secext-1.0.xsd";
String uta = prefixUri + "wssecurity-utility-1.0.xsd";
String ta = prefixUri + "username-token-profile-1.0#PasswordText";
Boolean isRequest = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(isRequest)
{
try
{
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:dd.SSS'Z'");
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
java.util.Date created = new java.util.Date();
java.util.Date expires = new java.util.Date(created.getTime() + (5l * 60l * 1000l));
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
SOAPHeader soapHeader = soapEnv.getHeader();
if (soapHeader == null)
soapHeader = soapEnv.addHeader();
SOAPFactory factory = SOAPFactory.newInstance();
SOAPElement securityElem = factory.createElement("Security", "o", uri);
securityElem.addAttribute(QName.valueOf("s:mustUnderstand"), "0");
SOAPElement timestampElem = factory.createElement("Timestamp", "u", uta);
timestampElem.addAttribute(QName.valueOf("xmlns:u"), uta);
timestampElem.addAttribute(QName.valueOf("Id"), "_0");
SOAPElement elem = factory.createElement("Created", "u", uta);
elem.addTextNode(formatter.format(created));
timestampElem.addChildElement(elem);
elem = factory.createElement("Expires", "u", uta);
elem.addTextNode(formatter.format(expires));
timestampElem.addChildElement(elem);
securityElem.addChildElement(timestampElem);
SOAPElement usernameElem = factory.createElement("UsernameToken", "o", uri);
elem = factory.createElement("Username", "o", uri);
elem.addTextNode("xxxxx");
usernameElem.addChildElement(elem);
elem = factory.createElement("Password", "o", uri);
elem.addTextNode("xxxxx");
elem.addAttribute(QName.valueOf("Type"), ta);
usernameElem.addChildElement(elem);
securityElem.addChildElement(usernameElem);
soapHeader.addChildElement(securityElem);
}
catch(Exception e)
{
System.out.println("Handler error!!!! - " + e);
}
}
return true;
}
public boolean handleFault(SOAPMessageContext context)
{
return true;
}
public void close(MessageContext context)
{
}
public Set<QName> getHeaders()
{
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,我编写了我的测试程序来附加处理程序并尝试调用Web服务.
import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
import org.tempuri.ServiceName;
import org.tempuri.IServiceName;
public class test
{
public static void main(String[] args)
throws Exception
{
ServiceName service = new ServiceName(new URL("https://url.to.service/services/ServiceName.svc?wsdl"), new QName("http://org.tempuri/", "ServiceName"));
service.setHandlerResolver(new HandlerResolver()
{
public List<Handler> getHandlerChain(PortInfo portInfo)
{
List<Handler> handlerList = new ArrayList<Handler>();
handlerList.add(new MyHeaderHandler());
return handlerList;
}
});
IServiceName binding = service.getBasicHttpBindingIServiceName();
ArrayLiist results = binding.getMyData("my parm");
System.out.println("Size: " + results.size());
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我在我执行binding.getMyData()的行中收到以下错误:
Exception in thread "main" java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
at com.sun.xml.ws.security.opt.impl.JAXBFilterProcessingContext.setJAXWSMessage(JAXBFilterProcessingContext.java:140)
at com.sun.xml.wss.jaxws.impl.SecurityPipeBase.secureOutboundMessage(SecurityPipeBase.java:389)
at com.sun.xml.wss.jaxws.impl.SecurityClientPipe.process(SecurityClientPipe.java:196)
at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:595)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:554)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:539)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:436)
at com.sun.xml.ws.client.Stub.process(Stub.java:248)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:135)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:109)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:118)
at $Proxy40.getM(Unknown Source)
at test.main(test.java:30)
Run Code Online (Sandbox Code Playgroud)
我尝试的每一种方法都在同一点上结束.我该如何解决这个问题?我无法弄清楚如何创建SecurityHeader放入标题.任何帮助将不胜感激.一个工作的例子会很棒.
谢谢!
这是一个老问题,但由于它有很多观点,这里有一个答案可以帮助人们继续前进。
您需要创建一个回调处理程序类。它看起来像下面这样:
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
public class MySecurityHandler implements CallbackHandler {
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
String userID = "xxxxxx";
NameCallback nc = (NameCallback) callbacks[i];
nc.setName(userID);
}
else {
if (callbacks[i] instanceof PasswordCallback) {
String password = "xxxx";
PasswordCallback pc = (PasswordCallback) callbacks[i];
pc.setPassword(password.toCharArray());
}
else {
throw new UnsupportedCallbackException(callbacks[i],
callbacks[i].getClass().getName());
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
将 WSDL 复制到同名的文件中,但将其设为 .xml 而不是 .wsdl。
修改新创建的xml文件。记下文件顶部的 targetNamespace,因为最后一步将需要它。需要将现有的 wsp:Policy 部分替换为类似于以下内容的部分,指定用户 ID/密码的回调处理程序。
<wsp:Policy wsu:Id="BasicHttpBinding_IAssessments_policy">
<wsp:ExactlyOne>
<wsp:All>
<sc:CallbackHandlerConfiguration wspp:visibility="private">
<sc:CallbackHandler classname="my.lib.MySecurityHandler"
name="usernameHandler"/>
<sc:CallbackHandler classname="my.lib.MySecurityHandler"
name="passwordHandler"/>
</sc:CallbackHandlerConfiguration>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
Run Code Online (Sandbox Code Playgroud)
修改您的应用程序的 wsit-client.xml 文件。在文件最后一行之前添加一个新行,如下所示。
<import location="relative path to xml file from step above"
namespace="targetNamespace from step above"/>
Run Code Online (Sandbox Code Playgroud)