CXF-08:自定义CXF拦截器来进行权限控制

自定义拦截器:
需要实现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 {
	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
headers = new ArrayList
(); 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 10:53:46 下午 org.apache.cxf.endpoint.ServerImpl initDestination
信息: Setting the server's publish address to be http://192.168.0.159:6786/sayHello
2016-10-24 22:53:46.368:INFO::jetty-7.4.2.v20110526
2016-10-24 22:53:46.440:INFO::Started [email protected]:6786 STARTING
2016-10-24 22:53:46.458:INFO::started o.e.j.s.h.ContextHandler{,null}
Web Service暴露成功!
----------------{javax.xml.ws.wsdl.port={http://impl.ws.cxf.fjava.org/}HelloWorldWsPort, org.apache.cxf.service.model.MessageInfo=[MessageInfo INPUT: {http://ws.cxf.fjava.org/}getAllFoods], org.apache.cxf.message.Message.PROTOCOL_HEADERS={Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[164], content-type=[text/xml; charset=UTF-8], Host=[192.168.0.159:6786], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 2.4.1]}, HTTP_CONTEXT_MATCH_STRATEGY=stem, org.apache.cxf.request.url=http://192.168.0.159:6786/sayHello, javax.xml.ws.wsdl.interface={http://ws.cxf.fjava.org/}HelloWorld, org.apache.cxf.request.uri=/sayHello, HTTP.REQUEST=(POST /sayHello)@2066284745 org.eclipse.jetty.server.Request@7b2900c9, org.apache.cxf.transport.https.CertConstraints=null, HTTP.CONFIG=null, Accept=*/*, org.apache.cxf.headers.Header.list=[], org.apache.cxf.message.Message.BASE_PATH=/sayHello, org.apache.cxf.message.Message.PATH_INFO=/sayHello, org.apache.cxf.continuations.ContinuationProvider=org.apache.cxf.transport.http_jetty.continuations.JettyContinuationProvider@40f2cb4a, javax.xml.ws.wsdl.service={http://impl.ws.cxf.fjava.org/}HelloWorldWs, org.apache.cxf.message.Message.IN_INTERCEPTORS=[org.apache.cxf.transport.https.CertConstraintsInterceptor@4008896], org.apache.cxf.message.Message.ENCODING=UTF-8, org.apache.cxf.message.Message.QUERY_STRING=null, HTTP.RESPONSE=HTTP/1.1 200 

, org.apache.cxf.security.SecurityContext=org.apache.cxf.transport.http.AbstractHTTPDestination$2@3f0731e7, org.apache.cxf.configuration.security.AuthorizationPolicy=null, org.apache.cxf.async.post.response.dispatch=true, org.apache.cxf.request.method=POST, javax.xml.ws.wsdl.operation={http://ws.cxf.fjava.org/}getAllFoods, org.apache.cxf.transport.Destination=org.apache.cxf.transport.http_jetty.JettyHTTPDestination@715d5504, org.apache.cxf.message.MessageFIXED_PARAMETER_ORDER=false, javax.xml.ws.wsdl.description=http://192.168.0.159:6786/sayHello?wsdl, org.apache.cxf.service.model.BindingMessageInfo=org.apache.cxf.service.model.BindingMessageInfo@2678b3c1, [email protected]{,null}, Content-Type=text/xml; charset=UTF-8}
十月 24, 2016 10:53:57 下午 org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
警告: Interceptor for {http://impl.ws.cxf.fjava.org/}HelloWorldWs#{http://ws.cxf.fjava.org/}getAllFoods has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: 没有Header,禁止调用!
	at org.fjava.cxf.ws.auth.AuthInterceptor.handleMessage(AuthInterceptor.java:38)
	at org.fjava.cxf.ws.auth.AuthInterceptor.handleMessage(AuthInterceptor.java:1)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
	at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:118)
	at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:318)
	at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:286)
	at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:939)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:875)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:247)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)
	at org.eclipse.jetty.server.Server.handle(Server.java:346)
	at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:589)
	at org.eclipse.jetty.server.HttpConnection$RequestHandler.content(HttpConnection.java:1065)
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:823)
	at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:214)
	at org.eclipse.jetty.server.HttpConnection.handle(HttpConnection.java:411)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:535)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:40)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:529)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: 没有Header,禁止调用!
	... 22 more

客户端输出:

十月 24, 2016 10:53:57 下午 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
信息: Creating Service {http://impl.ws.cxf.fjava.org/}HelloWorldWs from WSDL: http://192.168.0.159:6786/sayHello?wsdl
十月 24, 2016 10:53:57 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log
信息: Outbound Message
---------------------------
ID: 1
Address: http://192.168.0.159:6786/sayHello
Encoding: UTF-8
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: 
--------------------------------------
十月 24, 2016 10:53:57 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log
信息: Inbound Message
----------------------------
ID: 1
Response-Code: 500
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {Content-Length=[225], content-type=[text/xml;charset=UTF-8], Server=[Jetty(7.4.2.v20110526)]}
Payload: soap:Server没有Header,禁止调用!
--------------------------------------
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: 没有Header,禁止调用!
	at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:146)
	at com.sun.proxy.$Proxy23.getAllFoods(Unknown Source)
	at lee.ClientMain2.main(ClientMain2.java:26)
Caused by: org.apache.cxf.binding.soap.SoapFault: 没有Header,禁止调用!
	at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:75)
	at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:46)
	at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:35)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
	at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:104)
	at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:69)
	at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:34)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
	at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:762)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1582)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1467)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1375)
	at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:47)
	at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:188)
	at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
	at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:623)
	at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
	at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:510)
	at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:440)
	at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:343)
	at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:295)
	at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
	at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
	... 2 more

         * 2 . 在客户端Out拦截器改为自定义拦截器,增加Header元素来进行识别

                 在运行起来的CXF客户端不需要做任何的改动,只需要修改out拦截器:

import java.util.List;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.fjava.cxf.ws.Cat;
import org.fjava.cxf.ws.Entry;
import org.fjava.cxf.ws.Food;
import org.fjava.cxf.ws.HelloWorld;
import org.fjava.cxf.ws.StringFood;
import org.fjava.cxf.ws.User;
import org.fjava.cxf.ws.auth.AddHeaderInterceptor;
import org.fjava.cxf.ws.impl.HelloWorldWs;
public class ClientMain {
	public static void main(String[] args) {		
		//这是命令生成的类,该类的实例可当成工厂来使用
		HelloWorldWs factory = new HelloWorldWs();
		//无参的方法,返回的是远程Web Service服务端的代理,服务端不能关闭。
		HelloWorld helloWorld = factory.getHelloWorldWsPort();
		Client client = ClientProxy.getClient(helloWorld);
		client.getOutInterceptors().add(new AddHeaderInterceptor("admin","admin"));
		client.getOutInterceptors().add(new LoggingOutInterceptor());
		StringFood allFoods = helloWorld.getAllFoods();
		List entries = allFoods.getEntries();
		for (Entry entry : entries) {
			System.out.println(entry.getKey() + " " + entry.getValue().getDescribe());
		}
	}
}
                 增加你自己写的AddHeaderInterceptor拦截器继承AbstractPhaseInterceptor:
import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class AddHeaderInterceptor extends AbstractPhaseInterceptor {
	private String userId;
	private String password;
	public AddHeaderInterceptor(String userId, String password) {
		super(Phase.PREPARE_SEND);//在准备发送Soap消息时启用该拦截器
		this.userId = userId;
		this.password = password;
	}
	@Override
	public void handleMessage(SoapMessage msg) throws Fault {
		List
headers = msg.getHeaders(); //创建Document对象 Document document = DOMUtils.createDocument(); Element eleAuthHeader = document.createElement("authHeader"); //此处创建的元素应该与服务器的拦截元素相同 Element eleUserId = document.createElement("userId"); eleUserId.setTextContent(userId); Element elePassword = document.createElement("password"); elePassword.setTextContent(password); eleAuthHeader.appendChild(eleUserId); eleAuthHeader.appendChild(elePassword); /* * 上面代码生成了一个如下XML文档片段: * * * * */ //把ele元素包装成Header,并添加到SOAP消息的Header列表中。 headers.add(new Header(new QName("fjava"),eleAuthHeader)); } }

           自定义客户端拦截器后运行客户端

服务端输出:

十月 24, 2016 10:57:22 下午 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 10:57:22 下午 org.apache.cxf.endpoint.ServerImpl initDestination
信息: Setting the server's publish address to be http://192.168.0.159:6786/sayHello
2016-10-24 22:57:22.875:INFO::jetty-7.4.2.v20110526
2016-10-24 22:57:22.947:INFO::Started [email protected]:6786 STARTING
2016-10-24 22:57:22.964:INFO::started o.e.j.s.h.ContextHandler{,null}
Web Service暴露成功!
----------------{javax.xml.ws.wsdl.port={http://impl.ws.cxf.fjava.org/}HelloWorldWsPort, org.apache.cxf.service.model.MessageInfo=[MessageInfo INPUT: {http://ws.cxf.fjava.org/}getAllFoods], org.apache.cxf.message.Message.PROTOCOL_HEADERS={Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[264], content-type=[text/xml; charset=UTF-8], Host=[192.168.0.159:6786], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 2.4.1]}, HTTP_CONTEXT_MATCH_STRATEGY=stem, org.apache.cxf.request.url=http://192.168.0.159:6786/sayHello, javax.xml.ws.wsdl.interface={http://ws.cxf.fjava.org/}HelloWorld, org.apache.cxf.request.uri=/sayHello, HTTP.REQUEST=(POST /sayHello)@1572523437 org.eclipse.jetty.server.Request@5dbacdad, org.apache.cxf.transport.https.CertConstraints=null, HTTP.CONFIG=null, Accept=*/*, org.apache.cxf.headers.Header.list=[org.apache.cxf.binding.soap.SoapHeader@131548ee], org.apache.cxf.message.Message.BASE_PATH=/sayHello, org.apache.cxf.message.Message.PATH_INFO=/sayHello, org.apache.cxf.continuations.ContinuationProvider=org.apache.cxf.transport.http_jetty.continuations.JettyContinuationProvider@5a670b0b, javax.xml.ws.wsdl.service={http://impl.ws.cxf.fjava.org/}HelloWorldWs, org.apache.cxf.message.Message.IN_INTERCEPTORS=[org.apache.cxf.transport.https.CertConstraintsInterceptor@23062d8b], org.apache.cxf.message.Message.ENCODING=UTF-8, org.apache.cxf.message.Message.QUERY_STRING=null, HTTP.RESPONSE=HTTP/1.1 200 

, org.apache.cxf.security.SecurityContext=org.apache.cxf.transport.http.AbstractHTTPDestination$2@6a9812a3, org.apache.cxf.configuration.security.AuthorizationPolicy=null, org.apache.cxf.async.post.response.dispatch=true, org.apache.cxf.request.method=POST, javax.xml.ws.wsdl.operation={http://ws.cxf.fjava.org/}getAllFoods, org.apache.cxf.transport.Destination=org.apache.cxf.transport.http_jetty.JettyHTTPDestination@25efc201, org.apache.cxf.message.MessageFIXED_PARAMETER_ORDER=false, javax.xml.ws.wsdl.description=http://192.168.0.159:6786/sayHello?wsdl, org.apache.cxf.service.model.BindingMessageInfo=org.apache.cxf.service.model.BindingMessageInfo@1fa9e31c, [email protected]{,null}, Content-Type=text/xml; charset=UTF-8}
headers[org.apache.cxf.binding.soap.SoapHeader@131548ee]
userIdscom.sun.org.apache.xerces.internal.dom.DeepNodeListImpl@51b621a3
passwordscom.sun.org.apache.xerces.internal.dom.DeepNodeListImpl@c5a7e3e

客户端输出:

十月 24, 2016 11:04:14 下午 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
信息: Creating Service {http://impl.ws.cxf.fjava.org/}HelloWorldWs from WSDL: http://192.168.0.159:6786/sayHello?wsdl
十月 24, 2016 11:04:14 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log
信息: Outbound Message
---------------------------
ID: 1
Address: http://192.168.0.159:6786/sayHello
Encoding: UTF-8
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: adminadmin
--------------------------------------
蟹王汉堡 橙色,亮金色,我的宝贝,我的爱!
海绵金币 吃着金币样的甜甜饼,想着海绵宝宝赚的钱被扣了,哈哈哈,爽气!
一个汉堡 是三层的,有夹层哦!
火腿肠 这是章鱼哥从岸上偷运来的,据说很美味!

做一个权限控制,有用户名和密码的时候才允许调用 Web Service 该功能完成!

希望对你有帮助,祝你有一个好心情,加油!

若有错误、不全、可优化的点,欢迎纠正与补充;转载请注明出处!

你可能感兴趣的:(CXF)