zoukankan      html  css  js  c++  java
  • cxf添加拦截器应用

       

          项目中有时候也会做一些类似于权限验证的东西,拦截器也是一种实现方式。拦截器主要作用是做一些权限过滤,编码处理等。

           webService接口也可以上拦截器,我们也可以给webservice请求加权限判断功能;

           webservice分服务端和客户端,服务端和客户端都是可以加拦截器的,无论是服务端还是客户端,都分进,出(In,Out)拦截器;

          可以使用cxf内置拦截器,也可以自定义拦截器,无论是自定义的拦截器,还是CXF自带的拦截器,都必须实现Interceptor接口。

          下面分别从这两个方面来讲解:

          一、cxf内置拦截器

                 这里以日志拦截器为例:

                服务端的Server类:

               

     1 /**
     2  * 
     3  */
     4 package com.hik.webservice;
     5 
     6 import javax.xml.ws.Endpoint;
     7 
     8 import org.apache.cxf.interceptor.LoggingInInterceptor;
     9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
    10 import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
    11 
    12 import com.hik.webservice.impl.HelloWorldImpl;
    13 
    14 /**
    15  * @ClassName: Server
    16  * @Description: TODO
    17  * @author jed
    18  * @date 2017年7月30日上午10:26:16
    19  *
    20  */
    21 public class Server {
    22     
    23     public static void main(String[] args) {
    24         System.out.println("web Service start");
    25         HelloWorldImpl implementor = new HelloWorldImpl();
    26         String address="http://192.168.0.102/helloWorld";
    27         //Endpoint.publish(address, implementor);//JDK实现
    28         JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
    29         factoryBean.setAddress(address); //设置暴露地址
    30         factoryBean.setServiceClass(HelloWorld.class); //接口类
    31         factoryBean.setServiceBean(implementor); //设置实现类
    32         factoryBean.getInInterceptors().add(new LoggingInInterceptor()); //添加in拦截器  日志拦截器
    33         factoryBean.getOutInterceptors().add(new LoggingOutInterceptor()); // 添加out拦截器
    34         factoryBean.create();
    35         System.out.println("web Service started");
    36         
    37     }
    38 }
    View Code

       通过factoryBean对象可以获取拦截器组,添加进或者出拦截器。日志拦截器是经典的拦截器,开发经常用到。

       我们可以把客户端的请求,以及服务端返回的信息打印出来,可以打印控制台,也可以打印到执行文件;这里为了演示方便,直接搞无参的拦截器,

        打印到控制台; 

         执行下Server类:

    再来执行下客户端的Client类,结果:

    我们可以看到服务端server控制台有日志输出,仔细观察Server端的控制台:

     1 八月 05, 2017 9:21:35 上午 org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
     2 信息: Inbound Message
     3 ----------------------------
     4 ID: 1
     5 Address: http://192.168.0.102/helloWorld?wsdl
     6 Http-Method: GET
     7 Content-Type: 
     8 Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[192.168.0.102], User-Agent=[Java/1.7.0_79]}
     9 --------------------------------------
    10 八月 05, 2017 9:21:36 上午 org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
    11 信息: Inbound Message
    12 ----------------------------
    13 ID: 2
    14 Address: http://192.168.0.102/helloWorld
    15 Encoding: UTF-8
    16 Http-Method: POST
    17 Content-Type: text/xml; charset=UTF-8
    18 Headers: {Accept=[text/xml, multipart/related], connection=[keep-alive], Content-Length=[170], content-type=[text/xml; charset=UTF-8], Host=[192.168.0.102], SOAPAction=[""], User-Agent=[JAX-WS RI 2.2.4-b01]}
    19 Payload: <?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getRoles xmlns:ns2="http://webservice.hik.com/"/></S:Body></S:Envelope>
    20 --------------------------------------
    21 八月 05, 2017 9:21:37 上午 org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
    22 信息: Outbound Message
    23 ---------------------------
    24 ID: 2
    25 Response-Code: 200
    26 Encoding: UTF-8
    27 Content-Type: text/xml
    28 Headers: {}
    29 Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getRolesResponse xmlns:ns2="http://webservice.hik.com/"><return><item><key>jack</key><value><id>3</id><roleName>程序员</roleName></value></item><item><key>admin</key><value><id>1</id><roleName>技术总监</roleName></value><value><id>2</id><roleName>产品经理</roleName></value></item></return></ns2:getRolesResponse></soap:Body></soap:Envelope>
    30 --------------------------------------
    View Code

    这里的打印出来的就是日志信息:Inbound 进信息  Outbound 是出信息,进的时候,大家会看到有个Headers SOAP消息。后面我们可以在里面加我们的数据;

    在Outbound Message里,Payload消息里我们可以找到webservice返回的数据 SOAP消息;

    客户端也可以加进出拦截器,修改Client代码:

    我们用到了ClientProxy,客户端代理

    请求的时候,可以看到控制台的日志信息:(日志和服务端一样)

     1 八月 05, 2017 10:05:22 上午 org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
     2 信息: Creating Service {http://webservice.hik.com/}HelloWorldService from WSDL: http://192.168.0.102/helloWorld?wsdl
     3 八月 05, 2017 10:05:22 上午 org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
     4 信息: Outbound Message
     5 ---------------------------
     6 ID: 1
     7 Address: http://192.168.0.102/helloWorld
     8 Encoding: UTF-8
     9 Http-Method: POST
    10 Content-Type: text/xml
    11 Headers: {Accept=[*/*], SOAPAction=[""]}
    12 Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getRoles xmlns:ns2="http://webservice.hik.com/"/></soap:Body></soap:Envelope>
    13 --------------------------------------
    14 八月 05, 2017 10:05:23 上午 org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
    15 信息: Inbound Message
    16 ----------------------------
    17 ID: 1
    18 Response-Code: 200
    19 Encoding: UTF-8
    20 Content-Type: text/xml; charset=UTF-8
    21 Headers: {content-type=[text/xml; charset=UTF-8], Date=[Sat, 05 Aug 2017 02:05:22 GMT], Server=[Jetty(9.2.15.v20160210)], transfer-encoding=[chunked]}
    22 Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getRolesResponse xmlns:ns2="http://webservice.hik.com/"><return><item><key>jack</key><value><id>3</id><roleName>程序员</roleName></value></item><item><key>admin</key><value><id>1</id><roleName>技术总监</roleName></value><value><id>2</id><roleName>产品经理</roleName></value></item></return></ns2:getRolesResponse></soap:Body></soap:Envelope>
    23 --------------------------------------
    24 jack:
    25 3,程序员 
    26 
    27 admin:
    28 1,技术总监 
    29 2,产品经理 
    View Code

         二、自定义拦截器

               根据特殊需求,可能需自定义拦截器。如:客户端访问服务端webservice接口要加权限认证。

              实现思路:

             我们可以通过在SOAP消息的Header头信息中添加自定义信息,然后发送到服务端端,服务器端通过获取

              Header头消息,然后进行认证;这里的添加消息,和获取消息认证,我们都是通过自定义拦截器来实现;

            首先是服务器端:

           我们自定义拦截器:MyInterceptor  继承AbstractPhaseInterceptor (最终也是实现Interceptor接口)即可。实现handleMessage方法即可。

           自定义实现的拦截器:我们主要是获取Header头消息,然后获取userName和password节点,然后获取值,进行权限判断,假如认证不通过,我们抛出异常;

           

     1 /**
     2  * 
     3  */
     4 package com.hik.interceptor;
     5 
     6 
     7 import java.util.List;
     8 
     9 import org.apache.cxf.binding.soap.SoapMessage;
    10 import org.apache.cxf.headers.Header;
    11 import org.apache.cxf.interceptor.Fault;
    12 import org.apache.cxf.phase.AbstractPhaseInterceptor;
    13 import org.apache.cxf.phase.Phase;
    14 import org.w3c.dom.Element;
    15 import org.w3c.dom.NodeList;
    16 
    17 /**
    18  * @ClassName: MyInterceptor
    19  * @Description: 自定义拦截器
    20  * @author jed
    21  * @date 2017年8月5日上午10:20:09
    22  *
    23  */
    24 public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
    25     /**
    26      * 
    27      */
    28     public MyInterceptor() {
    29         // 在调用方法之前调用拦截器
    30         super(Phase.PRE_INVOKE);
    31     }
    32 
    33     public void handleMessage(SoapMessage message) throws Fault {
    34         List<Header> heads = message.getHeaders();
    35         if(heads==null|| heads.size()==0){
    36             throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截"));
    37         }
    38         Header firstHeader = heads.get(0);
    39         Element element = (Element) firstHeader.getObject();
    40         NodeList userIds = element.getElementsByTagName("userName");
    41         NodeList userPasses = element.getElementsByTagName("password");
    42         if(userIds.getLength()!=1){
    43             throw new Fault(new IllegalArgumentException("用户名格式不对"));
    44         }
    45         if(userPasses.getLength()!=1){
    46             throw new Fault(new IllegalArgumentException("密码格式不对"));
    47         }
    48         
    49         String userId = userIds.item(0).getTextContent();
    50         String userPass = userPasses.item(0).getTextContent();
    51         if(!userId.equals("admin")|| !userPass.equals("12345")){
    52             throw new Fault(new IllegalArgumentException("用户名或者密码不正确"));
    53         }
    54     }
    55 
    56 }
    View Code

    在Server类里,我们要添加一个in 拦截器,在进入的时候,我们要进行验证;

     1 /**
     2  * 
     3  */
     4 package com.hik.webservice;
     5 
     6 import javax.xml.ws.Endpoint;
     7 
     8 import org.apache.cxf.interceptor.LoggingInInterceptor;
     9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
    10 import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
    11 
    12 import com.hik.interceptor.MyInterceptor;
    13 import com.hik.webservice.impl.HelloWorldImpl;
    14 
    15 /**
    16  * @ClassName: Server
    17  * @Description: TODO
    18  * @author jed
    19  * @date 2017年7月30日上午10:26:16
    20  *
    21  */
    22 public class Server {
    23     
    24     public static void main(String[] args) {
    25         System.out.println("web Service start");
    26         HelloWorldImpl implementor = new HelloWorldImpl();
    27         String address="http://192.168.0.102/helloWorld";
    28         //Endpoint.publish(address, implementor);//JDK实现
    29         JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
    30         factoryBean.setAddress(address); //设置暴露地址
    31         factoryBean.setServiceClass(HelloWorld.class); //接口类
    32         factoryBean.setServiceBean(implementor); //设置实现类
    33         factoryBean.getInInterceptors().add(new LoggingInInterceptor()); //添加in拦截器  日志拦截器
    34         factoryBean.getOutInterceptors().add(new LoggingOutInterceptor()); // 添加out拦截器
    35         
    36         factoryBean.getInInterceptors().add(new MyInterceptor());// 添加自定义拦截器
    37         factoryBean.create();
    38         System.out.println("web Service started");
    39         
    40     }
    41 }
    View Code

    客户端代码:

    我们同样要添加一个自定义拦截器:AddHeaderInterceptor,主要是在拦截器里创建头消息;请求服务器端传入头信息为服务器接收验证。

     
     1 /**
     2  * 
     3  */
     4 package com.hik.interceptor;
     5 
     6 import java.util.List;
     7 
     8 import javax.xml.namespace.QName;
     9 
    10 import org.apache.cxf.binding.soap.SoapMessage;
    11 import org.apache.cxf.headers.Header;
    12 import org.apache.cxf.helpers.DOMUtils;
    13 import org.apache.cxf.interceptor.Fault;
    14 import org.apache.cxf.phase.AbstractPhaseInterceptor;
    15 import org.apache.cxf.phase.Phase;
    16 import org.w3c.dom.Document;
    17 import org.w3c.dom.Element;
    18 
    19 
    20 /**
    21  * @ClassName: AddHeaderInterceptor
    22  * @Description: TODO
    23  * @author jed
    24  * @date 2017年8月5日上午10:59:13
    25  *
    26  */
    27 public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
    28 
    29     private String userName;
    30     private String password;
    31     
    32     /**
    33      * @param userName
    34      * @param password
    35      */
    36     public AddHeaderInterceptor(String userName, String password) {
    37         super(Phase.PREPARE_SEND); // 发送SOAP消息之前调用拦截器
    38         this.userName = userName;
    39         this.password = password;
    40     }
    41 
    42     public void handleMessage(SoapMessage message) throws Fault {
    43         List<Header> heads = message.getHeaders();
    44         Document doc = DOMUtils.createDocument();
    45         Element ele = doc.createElement("authHeader");
    46         Element idElement = doc.createElement("userName");
    47         idElement.setTextContent(userName);
    48         Element passElement = doc.createElement("password");
    49         passElement.setTextContent(password);
    50         ele.appendChild(idElement);
    51         ele.appendChild(passElement);
    52         
    53         heads.add(new Header(new QName("admin"), ele));
    54     }
    55 
    56 
    57 }
    View Code

     Client类里我们要修改下,加下Out 拦截器:

     1 /**
     2  * 
     3  */
     4 package com.hik.webservice;
     5 import java.util.List;
     6 
     7 import org.apache.cxf.frontend.ClientProxy;
     8 import org.apache.cxf.interceptor.LoggingInInterceptor;
     9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
    10 
    11 import com.hik.interceptor.AddHeaderInterceptor;
    12 /**
    13  * @ClassName: Client
    14  * @Description: TODO
    15  * @author jed
    16  * @date 2017年7月30日下午1:58:36
    17  *
    18  */
    19 public class Client {
    20 
    21     public static void main(String[] args) {
    22         HelloWorldService service = new HelloWorldService();
    23         HelloWorld helloWorld = service.getHelloWorldPort(); //代理
    24         org.apache.cxf.endpoint.Client client =ClientProxy.getClient(helloWorld);
    25         //client.getInInterceptors().add(new LoggingInInterceptor()); // 添加in拦截器   日志拦截器
    26         client.getOutInterceptors().add(new AddHeaderInterceptor("admin", "12345")); // 添加自定义拦截器
    27         client.getOutInterceptors().add(new LoggingOutInterceptor()); // 添加out拦截器
    28         //org.apache.cxf.frontend.ClientProxy
    29         //System.out.println(helloWorld.say("你好!"));
    30         /*User user = new User();
    31         user.setUserName("lili");
    32         user.setPassword("123456"); 
    33         List<Role> roleList = helloWorld.getRoleByUser(user);
    34         for(Role role : roleList){
    35             System.out.println(role.getId()+" , "+role.getRoleName());
    36         }*/
    37         MyRoleArray array = helloWorld.getRoles();
    38         List<MyRole> roleList = array.item;
    39         for(int i=0;i<roleList.size();i++){
    40             MyRole mr = roleList.get(i);
    41             System.out.println(mr.key+":");
    42             for(Role r: mr.getValue()){
    43                 System.out.println(r.getId()+","+r.getRoleName()+" ");
    44             }
    45             System.out.println();
    46         }
    47     }
    48 }
    View Code

    这样就完整了自定义拦截器实现权限认证;先运行Server类,和以前一样;

    客户端日志打印:

    服务端日志信息:

    假如我们把  client.getOutInterceptors().add(new AddHeaderInterceptor("admin","123")); // 添加自定义拦截器

    密码改成 123 

    然后运行Client类,会报错;用户名密码不正确。

  • 相关阅读:
    Prometheus服务发现
    持久化查询
    PromQL进阶
    PromQL基础
    Prometheus概述
    监控系统概念
    zabbix5x解决中文字体问题
    allure 插件新手 demo
    关于时间复杂度~
    IIS发布网站Microsoft JET Database Engine 错误 '80004005'的解决办法,基于Access数据库
  • 原文地址:https://www.cnblogs.com/jedjia/p/cxf_interceptor.html
Copyright © 2011-2022 走看看