前言:
我们发布了一个服务,怎样保证我发布的服务不被所有人调用,用权限控制服务的调用,需要这样做?
cxf拦截器提供了这样的解决方法。下图来源于疯狂Java—cxf视频教程
从图中可以看出,cxf拦截器分为四种:服务端in,out拦截器;客户端in,out拦截器。
cxf有自带的拦截器,同时我们也可以自定义拦截器,下面我们编写一个自定义拦截器
package com.dqjb.util;
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;
/**
* 自定义拦截器
*
* @author wujialing
* @version V1.20,2015年4月21日 下午3:30:10
* @see [相关类/方法]
* @since V1.20
* @depricated
*/
public class AuthIntercepter extends AbstractPhaseInterceptor
{
public AuthIntercepter()
{
//调用之前进行拦截
super(Phase.PRE_INVOKE);
}
//handleMessage里面的形参就是被拦截到的soap消息
@Override
public void handleMessage(SoapMessage msg)
throws Fault
{
List headers = msg.getHeaders() ;
if (headers != null && headers.size() > 0)
{
Header header = headers.get(0);
Element element = (Element)header.getObject();
NodeList userIds = element.getElementsByTagName("userId");
NodeList userPasses = element.getElementsByTagName("userPass");
System.err.println("用户名:"+userIds.item(0).getTextContent());
System.err.println("密码:"+userPasses.item(0).getTextContent());
}
System.err.println("调用之前拦截器");
}
}
自定义拦截器需要继承AbstractPhaseInterceptor并且重写handleMessage方法,该方法就是你 拦截的业务逻辑,而构造方法中
super(Phase.PRE_INVOKE);
这一句代码,就是设置进入拦截器的时机。
下面分别服务端和客户端添加in和out拦截器:
服务端:
package com.dqjb.ws;
import javax.xml.ws.Endpoint;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import com.dqjb.util.AuthIntercepter;
import com.dqjb.ws.imlp.HelloWorldImpl;
public class WsPublish
{
public static void main(String[] args)
{
HelloWorld helloWorld = new HelloWorldImpl();
EndpointImpl en = (EndpointImpl)Endpoint.publish("http://10.114.73.30:8080/helloWorld", helloWorld);
en.getInInterceptors().add(new AuthIntercepter());//添加服务端in拦截器 自定义拦截器
en.getOutInterceptors().add(new LoggingOutInterceptor());//添加服务端out拦截器 日志拦截器
System.err.println("发布成功!");
}
}
服务端添加拦截器后,我们需要在客户端也加入拦截器,并在soap的header元素中添加用户名,密码信息。
package util;
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.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* 客户端拦截器
*
* @author wujialing
* @version V1.20,2015年4月21日 下午4:13:33
* @see [相关类/方法]
* @since V1.20
* @depricated
*/
public class AddHeaderIntercepter extends AbstractPhaseInterceptor
{
private String userId ;
private String userPass ;
public AddHeaderIntercepter(String userId, String userPass)
{
super(Phase.PREPARE_SEND); //在准备发送soap消息的时候调用
this.userId = userId;
this.userPass = userPass ;
}
@Override
public void handleMessage(SoapMessage msg)
throws Fault
{
List headers = msg.getHeaders();
//创建一个doc对象
Document doc = org.apache.cxf.helpers.DOMUtils.createDocument();
Element ele = doc.createElement("authHeader");
//此处创建的元素应按照服务端的要求创建
Element idEle = doc.createElement("userId");
idEle.setTextContent(userId);
Element passEle = doc.createElement("userPass");
passEle.setTextContent(userPass);
ele.appendChild(idEle);
ele.appendChild(passEle);
/*
* 上面代码生成一个XML片段
*/
headers.add(new Header(new QName("dqjq"), ele));
}
}
客户端调用时添加拦截器:
package test;
import java.util.List;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import util.AddHeaderIntercepter;
import com.dqjb.ws.HelloWorld;
import com.dqjb.ws.Task;
import com.dqjb.ws.User;
import com.dqjb.ws.imlp.HelloWorldWS;
public class TestClient
{
public static void main(String[] args)
{
HelloWorldWS ws= new HelloWorldWS();
HelloWorld helloWorld = ws.getHelloWorldImplPort();
//客户端添加拦截器
Client client = ClientProxy.getClient(helloWorld);
client.getOutInterceptors().add(new AddHeaderIntercepter("wujialing","123")); //客户端添加自定义拦截器
client.getOutInterceptors().add(new LoggingOutInterceptor());//添加默认拦截器
System.err.println(helloWorld.sayHi("OK!"));
User u = new User() ;
u.setAge(21);
u.setName("小明");
u.setPost("CXY");
List tasks = helloWorld.getTaskByUser(u);
for (Task task : tasks)
{
System.out.println(task.getTaskName());
}
//HashMap result = helloWorld.getAllTasks2();
}
}
通过对服务端客户端拦截器的编写及调用,我们即可以实现cxf服务调用权限的实现。