Apache CXF自定义拦截器实现权限控制

一. 拦截器

在我们学习Java的征途中碰到了很多拦截器: Servlet中的Filter就是一个拦截器, Struts2中也有拦截器,.

CXF中的拦截器其基本原理还是使用动态代理, 我们可以在不对核心模块进行修改的情况下, 动态添加一些功能, 从而降低代码的耦合性.

二. CXF拦截器

CXF通过在Interceptor中对消息进行特殊处理, 实现了很多重要功能模块, 例如: 日志记录, soap消息处理, 消息的压缩处理.

下面我们使用一个例子介绍CXF Log拦截器: 

1. 服务端添加日志拦截器:

 

public class MyServer { 
    public static void main(String[] args) { 
        HelloService helloService = new HelloServiceImpl(); 
        EndpointImpl epi = (EndpointImpl)Endpoint.publish("http://localhost/sayHello", helloService); 
        epi.getInInterceptors().add(new LoggingInInterceptor()); // 添加服务器端in log拦截器 
        epi.getOutInterceptors().add(new LoggingOutInterceptor()); // 添加服务器端out log拦截器 
        System.out.println("Web Service 暴露成功"); 
    } 
}

 

2. 客户端添加日志拦截器

 

public class MyClient { 
    public static void main(String[] args) { 
        HelloServiceImplService factory = new HelloServiceImplService(); 
        HelloService helloService = factory.getHelloServiceImplPort(); 
   
        Client client = ClientProxy.getClient(helloService); 
        client.getInInterceptors().add(new LoggingInInterceptor()); // 添加客户端in log拦截器 
        client.getOutInterceptors().add(new LoggingOutInterceptor()); // 添加客户端out log拦截器 
   
        System.out.println(helloService.sayHello("zhangsan")); 
    } 
}

 

其他程序代码请参考上一篇博客: http://blog.csdn.net/zdp072/article/details/27829831

客户端需要引入以下jar包: cxf-2.2.10.jar  wsdl4j-1.6.2.jar  XmlSchema-1.4.5.jar

 

3. 日志如下:

- - 服务端

2014-6-7 23:04:28 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass 
信息: Creating Service {http://impl.service.zdp.com/}HelloServiceImplService from class com.zdp.service.HelloService 
2014-6-7 23:04:28 org.apache.cxf.endpoint.ServerImpl initDestination 
信息: Setting the server's publish address to be http://localhost:80/sayHello 
2014-06-07 23:04:28.718::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog 
2014-06-07 23:04:28.726::INFO:  jetty-6.1.21 
2014-06-07 23:04:28.799::INFO:  Started SelectChannelConnector@localhost:80 
Web Service 暴露成功

- - 客户端

2014-6-7 23:05:26 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL 
信息: Creating Service {http://impl.service.zdp.com/}HelloServiceImplService from WSDL: http://localhost/sayHello?wsdl 
2014-6-7 23:05:26 org.apache.cxf.interceptor.LoggingOutInterceptor$LoggingCallback onClose 
信息: Outbound Message 
--------------------------- 
ID: 1 
Address: http://localhost/sayHello 
Encoding: UTF-8 
Content-Type: text/xml 
Headers: {SOAPAction=[""], Accept=[*/*]} 
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHello xmlns:ns2="http://service.zdp.com/"><arg0>zhangsan</arg0></ns2:sayHello></soap:Body></soap:Envelope> 
-------------------------------------- 
2014-6-7 23:05:26 org.apache.cxf.interceptor.LoggingInInterceptor logging 
信息: Inbound Message 
---------------------------- 
ID: 1 
Response-Code: 200 
Encoding: UTF-8 
Content-Type: text/xml; charset=utf-8 
Headers: {content-type=[text/xml; charset=utf-8], Content-Length=[275], Server=[Jetty(6.1.21)]} 
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org /soap/envelope /"><soap:Body><ns1:sayHelloResponse xmlns:ns1="http: //service.zdp.com/"><return>zhangsan, 您好! 现在的时间 是: Sat Jun 07 23:05:26 CST 2014</return></ns1:sayHelloResponse></soap:Body></soap:Envelope> 
-------------------------------------- 
zhangsan, 您好! 现在的时间是: Sat Jun 07 23:05:26 CST 2014

三. CXF自定义拦截器

如何使用CXF进行权限控制呢?

思路: 服务器端要求input消息总是携带有用户名, 密码信息, 如果没有用户名和密码信息, 直接拒绝调用.\

 

代码实现:

1. 服务器端拦截器:

 

/**  
 * 服务端权限拦截器
 */ 
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> { 
   
    public AuthInterceptor() { 
        super(Phase.PRE_INVOKE); //拦截器在调用方法之前拦截SOAP消息 
    } 
       
    // 拦截器操作 
    @Override 
    public void handleMessage(SoapMessage msg) throws Fault { 
        System.out.println("come to auth interceptor..."); 
        //获取SOAP消息的所有Header 
        List<Header> headers = msg.getHeaders(); 
           
        if(headers == null || headers.size() < 1) { 
            throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截")); 
        } 
        //获取Header携带是用户和密码信息 
        Header firstHeader = headers.get(0); 
        Element element = (Element) firstHeader.getObject(); 
           
        NodeList userNameElement = element.getElementsByTagName("userName"); 
        NodeList passwordElement = element.getElementsByTagName("password"); 
           
        if (userNameElement.getLength() != 1) { 
            throw new Fault(new IllegalArgumentException("用户名格式不对")); 
        } 
               
        if (passwordElement.getLength() != 1) { 
            throw new Fault(new IllegalArgumentException("用户密码格式不对")); 
        } 
           
        //获取元素的文本内容 
        String userName = userNameElement.item(0).getTextContent(); 
        String password = passwordElement.item(0).getTextContent(); 
           
        // 实际项目中, 应该去查询数据库, 该用户名,密码是否被授权调用该webservice 
        if (!userName.equals("zhangsan") || !password.equals("123456")) { 
            throw new Fault(new IllegalArgumentException("用户名或密码不正确")); 
        } 
    } 
}

 

2. 客户端拦截器

/**
 * 客户端拦截器(在xml片段中加头部)
 */ 
public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage>{ 
       
    private String userName; 
    private String password; 
       
    public AddHeaderInterceptor(String userName, String password) { 
        super(Phase.PREPARE_SEND); 
        this.userName = userName; 
        this.password = password;  
    } 
   
    @Override 
    public void handleMessage(SoapMessage msg) throws Fault { 
           
        List<Header> headers = msg.getHeaders(); 
           
        //创建Document对象 
        Document document = DOMUtils.createDocument(); 
        Element element = document.createElement("authHeader");  
           
        //配置服务器端Head信息的用户密码 
        Element userNameElement= document.createElement("userName");  
        userNameElement.setTextContent(userName); 
        Element passwordElement = document.createElement("password");  
        passwordElement.setTextContent(password); 
           
        element.appendChild(userNameElement); 
        element.appendChild(passwordElement); 
        headers.add(new Header(new QName(""), element)); 
        /**
         * 生成的XML文档
         * <authHeader>
         *      <userName>zhangsan</userName>
         *      <password>123456</password>
         * </authHeader>
         */ 
    } 

3. 服务端

 

public class MyServer { 
    public static void main(String[] args) { 
        HelloService helloService = new HelloServiceImpl(); 
        EndpointImpl epi = (EndpointImpl)Endpoint.publish("http://localhost/sayHello", helloService); 
   
        // 添加服务器端in 权限拦截器, 该AuthInterceptor就会负责检查用户名, 密码是否正确 
        epi.getInInterceptors().add(new AuthInterceptor());  
        System.out.println("Web Service 暴露成功"); 
    } 
}

 

4. 客户端

 

public class MyClient { 
    public static void main(String[] args) { 
        HelloServiceImplService factory = new HelloServiceImplService(); 
           
        // 此处返回的只是webservice的代理 
        HelloService helloService = factory.getHelloServiceImplPort(); 
        Client client = ClientProxy.getClient(helloService); 
        client.getOutInterceptors().add(new AddHeaderInterceptor("zhangsan", "123456"));  
        System.out.println(helloService.sayHello("zhangsan")); 
    } 
}

 

posted @ 2014-12-01 16:16  贝壳风铃  阅读(1228)  评论(1)    收藏  举报