添加自定义拦截器,CXF允许程序员自己操作SOAP协议。
Envelope可分为两部分,Header(可选) 与Body,通过自定义拦截器,可在Header部分里添加认证信息。
服务端代码:
需要实现PhaseInterceptor,但一般继承抽象类AbstractPhaseInterceptor就可以了。
package com.skymr.hello.ws.interceptor;
import java.util.List;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
public AuthInterceptor() {
//调用之前认证
super(Phase.PRE_INVOKE);
}
/**
* 取出Header头进行认证
*/
public void handleMessage(SoapMessage msg) throws Fault {
List<Header> headers = msg.getHeaders();
if(headers == null || headers.size()==0){
throw new Fault(new IllegalArgumentException("找不到认证信息"));
}
Header header = headers.get(0);
Element auth = (Element)header.getObject();
NodeList uNl = auth.getElementsByTagName("username");
NodeList uPw = auth.getElementsByTagName("password");
if(uNl.getLength() < 1){
throw new Fault(new IllegalArgumentException("找不到用户名信息"));
}
if(uPw.getLength() < 1){
throw new Fault(new IllegalArgumentException("找不到密码信息"));
}
String userName = uNl.item(0).getTextContent();
String password = uPw.item(0).getTextContent();
if("admin".equals(userName) && "admin".equals(password)){
System.out.println("认证成功");
}
else{
throw new Fault(new IllegalArgumentException("认证失败"));
}
}
}
客户端代码
package com.skymr.hello.ws.interceptor;
import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
protected String userName;
protected String password;
public AuthInterceptor(String userName, String password) {
//发送前拦截
super(Phase.PREPARE_SEND);
this.userName = userName;
this.password = password;
}
/**
* 生成认证信息
* <head>
* <authrity>
* <username></username>
* <password></password>
* </authrity>
* </head>
*/
public void handleMessage(SoapMessage msg) throws Fault {
System.out.println("--------------");
List<Header> headers = msg.getHeaders();
Document doc = DOMUtils.createDocument();
Element auth = doc.createElement("authrity");
Element userNameNode = doc.createElement("username");
Element passwordNode = doc.createElement("password");
userNameNode.setTextContent(userName);
passwordNode.setTextContent(password);
auth.appendChild(userNameNode);
auth.appendChild(passwordNode);
//QName的参数随便取个名字
headers.add(0,new Header(new QName("head"), auth));
}
}
服务端和客户端添加各自拦截器后进行测试:
服务端添加:是在spring与CXF整合的基础上
<jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld" />
<jaxws:endpoint id="userOp" implementor="#userOperator" address="/UserOperator" ></jaxws:endpoint>
<bean id="logInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<!-- 自定义拦截器,认证拦截 -->
<bean id="authInterceptor" class="com.skymr.hello.ws.interceptor.AuthInterceptor"></bean>
<cxf:bus>
<cxf:inInterceptors>
<ref bean="logInterceptor"/>
<ref bean="authInterceptor"/>
</cxf:inInterceptors>
</cxf:bus>
客户端添加:
HelloWorldws factory = new HelloWorldws();
HelloWorld hw = factory.getHelloWorldBeanPort();
Client client = ClientProxy.getClient(hw);
client.getOutInterceptors().add(new AuthInterceptor("admin","admin"));
client.getOutInterceptors().add(new LoggingOutInterceptor());
System.out.println(hw.sayHello("skymr"));
控制台输出:
九月 15, 2015 11:21:07 上午 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
INFO: Creating Service {http://impl.ws.hello.skymr.com/}helloWorldws from WSDL: http://192.168.2.102:8080/spring_cxf/doWS/HelloWorld?wsdl
--------------
九月 15, 2015 11:21:09 上午 org.apache.cxf.services.helloWorldws.HelloWorldBeanPort.HelloWorld
INFO: Outbound Message
---------------------------
ID: 1
Address: http://192.168.2.102:8080/spring_cxf/doWS/HelloWorld
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><authrity><username>admin</username><password>admin</password></authrity></soap:Header><soap:Body><ns2:sayHello xmlns:ns2="http://ws.hello.skymr.com/"><arg0>skymr</arg0></ns2:sayHello></soap:Body></soap:Envelope>
--------------------------------------
你好skymr,欢迎进入Web Service学习课程
取出SOAP消息:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<authrity>
<username>admin</username>
<password>admin</password>
</authrity>
</soap:Header>
<soap:Body>
...
</soap:Body>
</soap:Envelope>
自定义拦截器完成。