前言
有时候调用web service 会出现
Message does not conform to configured policy [ AuthenticationTokenPolicy(S) ]: No Security Header found
这种错误。
以在 soapui 调用的结果来看, 会出现例如以下的返回
出现这种错误的原因 是webservice 的服务端须要提供 soap 认证的表头。
举例来说。 可能须要加上例如以下的认证头:
<soapenv:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1"> <wsse:UsernameToken> <wsse:Username>UserName</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Password</wsse:Password> </wsse:UsernameToken> </wsse:Security> </soapenv:Header>
(这个细部的格式和服务端的要求有关, 详细的username和pass也是服务端提供的)
在sopaui 调用的时候, 加上相似, 就能呼叫成功了。
在soapui 调用, 能够用以上方式来做。
在把wsdl 转为java 后。 又该怎样加上认证的头信息呢?
cxf 加上认证头
(以上的认证头。 比較接近cxf 的调用方式。
)
假设使用的是cxf生产的客户端的代码。
(怎样生成,參考 CXF 生成Web Service Client(将WSDl 转化成 Java代码))
在 _Client 调用的时候加上 例如以下代码:(在方法调用的代码之前)
Map<String, Object> props = new HashMap<String, Object>(); props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); props.put(WSHandlerConstants.PASSWORD_TYPE,WSConstants.PW_TEXT); props.put(WSHandlerConstants.USER, "UserName"); props.put(WSHandlerConstants.PW_CALLBACK_CLASS, PasswordHandler.class.getName()); WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props); Client client = ClientProxy.getClient(port); client.getOutInterceptors().add(wssOut);
在client 的java 文件里, 新增下面内部类
public static class PasswordHandler implements CallbackHandler { public void handle(javax.security.auth.callback.Callback[] callbacks) { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback)callbacks[i]; pc.setPassword("password"); } } }
Axis2 加上认证头
针对以上的认证头在axis2 产生的java 文件里怎样加入呢(Axis2自己主动产生的java 文件并不会自己主动产生main的測试文件, 须要自己写。 XXXXProxy.java 这是供调用的类文件。 只是这些和加入认证头关系不大)
axis2会产生一个 XXXXPortBindingStub.java 的文件。
这里面的内容就是实际的方法体。
找到我们须要调用的那个方法体:
在方法调用之前。加入下面代码:
//Begin add for Header String AUTH_PREFIX = "wsse"; String AUTH_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; try{ SOAPElement wsSecHeaderElm = soapFactory.createElement("Security", AUTH_PREFIX, AUTH_NS); SOAPElement userNameTokenElm = soapFactory.createElement("UsernameToken",AUTH_PREFIX, AUTH_NS); SOAPElement userNameElm = soapFactory.createElement("Username",AUTH_PREFIX, AUTH_NS); SOAPElement passwdElm = soapFactory.createElement("Password",AUTH_PREFIX, AUTH_NS); passwdElm.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"); userNameElm.addTextNode("vend_bmc01"); passwdElm.addTextNode("mediatek"); userNameTokenElm.addChildElement(userNameElm); userNameTokenElm.addChildElement(passwdElm); wsSecHeaderElm.addChildElement(userNameTokenElm); SOAPHeaderElement soapHeaderElement = new SOAPHeaderElement(wsSecHeaderElm); soapHeaderElement.setMustUnderstand(true); _call.addHeader(soapHeaderElement); }catch(Exception e) { e.printStackTrace(); } //End add for Header ===》call method java.lang.Object _resp = _call.invoke(XXXX);
原理非常easy。 加上相似xml 的头, _call_addHeader
加上之后。再触发方法 _call.invoke