cxf添加拦截器应用

Posted 心和梦的方向

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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类,会报错;用户名密码不正确。

 

以上是关于cxf添加拦截器应用的主要内容,如果未能解决你的问题,请参考以下文章

WebService -- Java 实现之 CXF ( 添加系统预定义的拦截器)

cxf拦截器

SpringBoot+CXF 实现简单的webservice,并支持Basic验证

学习webservice之cxf:cxf日志拦截器

CXF拦截器(Interceptor)LoggingInInterceptor

CXF 自定义拦截器