自定义拦截器:
需要实现Interceptor接口,实际上,我们一般会继承AbstractPhaseInterceptor;
做一个权限控制,有用户名和密码的时候才允许调用 Web Service:
需要实现Interceptor接口,实际上,我们一般会继承AbstractPhaseInterceptor;
做一个权限控制,有用户名和密码的时候才允许调用 Web Service:
* 1 . 在服务器端将系统提供的In拦截器改为自定义拦截器
在运行起来的CXF服务端不需要做任何的改动,只需要修改In拦截器:
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.xml.ws.Endpoint;
import org.fjava.cxf.ws.HelloWorld;
import org.fjava.cxf.ws.auth.AuthInterceptor;
import org.fjava.cxf.ws.impl.HelloWorldWs;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
//发布Web Service
public class ServiceMain {
public static void main(String[] args) throws IOException{
HelloWorld hw = new HelloWorldWs();
//调用Endpoint的publish("本机地址","服务的提供者:一个Web Service对象")方法发布Web Service
EndpointImpl ep = (EndpointImpl) Endpoint.publish("http://192.168.0.159:6786/sayHello", hw);
//添加In拦截器,该AuthInterceptor负责检查用户名、密码是否正确
ep.getInInterceptors().add(new AuthInterceptor());
System.out.println("Web Service暴露成功!");
//暴露成功后可以被任何平台的任何语言调用
//检查调用地址http://192.168.*.*/sayHello?wsdl
}
}
增加你自己写的AuthInterceptor拦截器继承AbstractPhaseInterceptor:
import java.util.ArrayList;
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;
//通过PhaseInterceptor,可以指定拦截器在哪个阶段起作用。
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
public AuthInterceptor(){
//super表示显示调用父类有参数的构造器。
//显示调用父类构造器,程序将不会隐式调用父类无参的构造器。
//---父类构造器里方法AbstractPhaseInterceptor(String phase)
//---phase是指一个拦截阶段
//---CXF文档里有Phase类,这个类里有各个阶段
super(Phase.PRE_INVOKE);//该拦截器将会在"调用之前"拦截Soap消息。
}
//实现自己的拦截器时,需要实现handleMessage方法。
//handleMessage方法中的形参就是被拦截到的Soap消息。
//一旦程序获得了Soap消息,剩下的事情就可以解析Soap消息,或修改Soap消息。
@Override
public void handleMessage(SoapMessage msg) throws Fault{
//下面代码显示"调用之前"成功拦截了信息
System.out.println("----------------"+ msg);
//得到Soap消息的所有Header
List<Header> headers = new ArrayList<Header>();
try {
headers = msg.getHeaders();
} catch (Exception e) {
throw new Fault(new IllegalArgumentException("没有Header,禁止调用!"));
}
//如果根本没有Header
if(headers == null || headers.size() < 1 ){
throw new Fault(new IllegalArgumentException("没有Header,禁止调用!"));
}
System.out.println("headers" + headers);
//假如要求第一个Header携带了用户名、密码信息
Header firstHeader = headers.get(0);
Element ele = (Element)firstHeader.getObject();
NodeList userIds = ele.getElementsByTagName("userId");
NodeList passwords = ele.getElementsByTagName("password");
if(userIds == null || userIds.getLength() != 1){
throw new Fault(new IllegalArgumentException("用户名格式不正确!"));
}
if(passwords == null || passwords.getLength() != 1){
throw new Fault(new IllegalArgumentException("密码格式不正确!"));
}
System.out.println("userIds" + userIds);
System.out.println("passwords" + passwords);
//得到userId元素里的文本内容,以该内容作为用户名
String userId = userIds.item(0).getTextContent();
String password = passwords.item(0).getTextContent();
//实际项目中,是去查询数据库,该用户名、密码是否被授权访问该Web Service。
if(!"admin".equals(userId) && !"admin".equals(password)){
throw new Fault(new IllegalArgumentException("用户名、密码不正确!"));
}
}
}
若不写客户端拦截器则会报错:没有用户名与密码无法正常调用该接口(用户名、密码填写错误也会报错)
服务端输出:
十月 24, 2016 10:53:45 下午 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://impl.ws.cxf.fjava.org/}HelloWorldWs from class org.fjava.cxf.ws.HelloWorld
十月 24, 2016