项目中有时候也会做一些类似于权限验证的东西,拦截器也是一种实现方式。拦截器主要作用是做一些权限过滤,编码处理等。
webService接口也可以上拦截器,我们也可以给webservice请求加权限判断功能;
webservice分服务端和客户端,服务端和客户端都是可以加拦截器的,无论是服务端还是客户端,都分进,出(In,Out)拦截器;
可以使用cxf内置拦截器,也可以自定义拦截器,无论是自定义的拦截器,还是CXF自带的拦截器,都必须实现Interceptor接口。
下面分别从这两个方面来讲解:
一、cxf内置拦截器
这里以日志拦截器为例:
服务端的Server类:
1 /**
3 */
4 package com.hik.webservice;
6 import javax.xml.ws.Endpoint;
8 import org.apache.cxf.interceptor.LoggingInInterceptor;
9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
10 import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
12 import com.hik.webservice.impl.HelloWorldImpl;
14 /**
15 * @ClassName: Server
16 * @Description: TODO
17 * @author jed
18 * @date 2017年7月30日上午10:26:16
19 *
20 */
21 public class Server {
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");
37 }
通过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 --------------------------------------
这里的打印出来的就是日志信息: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,程序员
27 admin:
28 1,技术总监
29 2,产品经理
二、自定义拦截器
根据特殊需求,可能需自定义拦截器。如:客户端访问服务端webservice接口要加权限认证。
实现思路:
我们可以通过在SOAP消息的Header头信息中添加自定义信息,然后发送到服务端端,服务器端通过获取
Header头消息,然后进行认证;这里的添加消息,和获取消息认证,我们都是通过自定义拦截器来实现;
首先是服务器端:
我们自定义拦截器:MyInterceptor 继承AbstractPhaseInterceptor (最终也是实现Interceptor接口)即可。实现handleMessage方法即可。
自定义实现的拦截器:我们主要是获取Header头消息,然后获取userName和password节点,然后获取值,进行权限判断,假如认证不通过,我们抛出异常;
1 /**
3 */
4 package com.hik.interceptor;
7 import java.util.List;
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;
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 }
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 }
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 }
在Server类里,我们要添加一个in 拦截器,在进入的时候,我们要进行验证;
1 /**
3 */
4 package com.hik.webservice;
6 import javax.xml.ws.Endpoint;
8 import org.apache.cxf.interceptor.LoggingInInterceptor;
9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
10 import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
12 import com.hik.interceptor.MyInterceptor;
13 import com.hik.webservice.impl.HelloWorldImpl;
15 /**
16 * @ClassName: Server
17 * @Description: TODO
18 * @author jed
19 * @date 2017年7月30日上午10:26:16
20 *
21 */
22 public class Server {
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拦截器
36 factoryBean.getInInterceptors().add(new MyInterceptor());// 添加自定义拦截器
37 factoryBean.create();
38 System.out.println("web Service started");
40 }
客户端代码:
我们同样要添加一个自定义拦截器:AddHeaderInterceptor,主要是在拦截器里创建头消息;请求服务器端传入头信息为服务器接收验证。
1 /**
3 */
4 package com.hik.interceptor;
6 import java.util.List;
8 import javax.xml.namespace.QName;
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;
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>{
29 private String userName;
30 private String password;
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 }
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);
53 heads.add(new Header(new QName("admin"), ele));
54 }
Client类里我们要修改下,加下Out 拦截器:
1 /**
3 */
4 package com.hik.webservice;
5 import java.util.List;
7 import org.apache.cxf.frontend.ClientProxy;
8 import org.apache.cxf.interceptor.LoggingInInterceptor;
9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
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 {
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 }
这样就完整了自定义拦截器实现权限认证;先运行Server类,和以前一样;
客户端日志打印:
服务端日志信息:
假如我们把 client.getOutInterceptors().add(new AddHeaderInterceptor("admin","123")); // 添加自定义拦截器
密码改成 123
然后运行Client类,会报错;用户名密码不正确。
项目中有时候也会做一些类似于权限验证的东西,拦截器也是一种实现方式。拦截器主要作用是做一些权限过滤,编码处理等。
webService接口也可以上拦截器,我们也可以给webservice请求加权限判断功能;
webservice分服务端和客户端,服务端和客户端都是可以加拦截器的,无论是服务端还是客户端,都分进,出(In,Out)拦截器;
CXF拦截器类似Struts2的拦截器,后者是拦截和处理请求,前者是对发送和接收的sope消息进行处理,一般用于WS请求响应中的权限验证、日志记录,Soap消息处理,消息的压缩处理等;
这个拦截器可以直接访问和修改sope消息。
拿权限验证举例:
二、服务端添加拦截器
三种方式:JaxWsServerFactoryBean、Endpoint都可以通过getInInterceptors方法...
1、具体错误如下
五月 04, 2014 11:29:28 下午 org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://service.you.com/}IServiceSer...
今天写一个简单的拦截器,以webService接口为例:
背景:H5的一个项目,只要调用H5webService 接口下面的方法都会触发一个AuthorityInterceptor去验证是否调用类型是H5,session是否失效.
1.需要自己定义一个Interceptor,我定义的Interceptor去验证调用类型moduleType和session:
package com.lcc...