【WebService框架-CXF】——CXF拦截器

来源:互联网 发布:耐克淘宝官方旗舰店 编辑:程序博客网 时间:2024/06/05 14:07

背景

  当一个服务发布之后,只要有服务地址,我们就可以建立客户端对服务进行调用。如果服务的提供者想要对可以调用服务的客户端进行限制,如:只有某些客户可以调用此服务。这时候就会用到拦截器,来进行权限控制。
  明白了拦截器的应用场景,我们看看CXF的拦截器怎么用。

IN&OUT拦截器

这里写图片描述

从图中我们可以总结出,只要从一端发出消息时要进行拦截,就要使用OUT拦截器。如果要对接收的消息进行拦截就要使用IN拦截器。

在服务端添加IN拦截器和OUT拦截器

public class TestMain {    public  static  void main(String[] arg){        HelloWorld hw=new HelloWorldWS();               EndpointImpl eImpl=(EndpointImpl)Endpoint.publish("http://localhost:9009/HelloWorldWS", hw);        eImpl.getInInterceptors().add(new LoggingInInterceptor());        eImpl.getOutInterceptors().add(new LoggingOutInterceptor());        System.out.println("Web Service暴露成功!");    }}

调用客户端,之后在服务端查看打印结果

Inbound Message

通过LoggingInInterceptor()拦截到的信息

六月 18, 2016 9:18:40 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log信息: Inbound Message----------------------------ID: 3Address: http://localhost:9009/HelloWorldWSEncoding: UTF-8Http-Method: POSTContent-Type: text/xml; charset=UTF-8Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[185], content-type=[text/xml; charset=UTF-8], Host=[localhost:9009], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 2.4.0]}Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi xmlns:ns2="http://ws.tgb.com/"><arg0>许晨阳</arg0></ns2:sayHi></soap:Body></soap:Envelope>

Outbound Message

通过LoggingOutInterceptor()拦截到的信息

六月 18, 2016 9:18:40 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log信息: Outbound Message---------------------------ID: 3Encoding: UTF-8Content-Type: text/xmlHeaders: {}Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse xmlns:ns2="http://ws.tgb.com/"><return>许晨阳,你好!现在时间是:2016-06-18 09:18:40</return></ns2:sayHiResponse></soap:Body></soap:Envelope>

在客户端添加IN拦截器和OUT拦截器

此时相同的信息会在客户端打印出来。

public class ClientMain {    public static void main(String[] args){        //工厂,继承Service        HelloWorldWS factory=new HelloWorldWS();        //只是服务的代理        HelloWorld hw=factory.getHelloWorldWSPort();        //客户端拦截器        Client c= ClientProxy.getClient(hw);        c.getInInterceptors().add(new LoggingInInterceptor());        c.getOutInterceptors().add(new LoggingOutInterceptor());        System.out.println(hw.sayHi("许晨阳"));            }}
--------------------------------------六月 20, 2016 5:33:43 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log信息: Outbound Message---------------------------ID: 1Address: http://localhost:9009/HelloWorldWSEncoding: UTF-8Content-Type: text/xmlHeaders: {Accept=[*/*], SOAPAction=[""]}Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi xmlns:ns2="http://ws.tgb.com/"><arg0>许晨阳</arg0></ns2:sayHi></soap:Body></soap:Envelope>
--------------------------------------六月 20, 2016 5:33:43 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log信息: Inbound Message----------------------------ID: 1Response-Code: 200Encoding: UTF-8Content-Type: text/xml;charset=UTF-8Headers: {Content-Length=[252], content-type=[text/xml;charset=UTF-8], Server=[Jetty(7.3.1.v20110307)]}Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse xmlns:ns2="http://ws.tgb.com/"><return>许晨阳,你好!现在时间是:2016-06-20 05:33:43</return></ns2:sayHiResponse></soap:Body></soap:Envelope>

自定义拦截器

通过自定义拦截器,我们可以根据需求修改SOAP消息,进行权限控制。

public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {    public AuthInterceptor(String phase) {        super(phase);    }    @Override    public void handleMessage(SoapMessage soapMessage) throws Fault {                List<Header> headers=soapMessage.getHeaders();        if(headers==null || headers.size()<1){           throw new Fault(new IllegalArgumentException("没有Header,不能调用"));        }        Header firstHeader=headers.get(0);        Element ele=(Element)firstHeader.getObject();        NodeList userIds=ele.getElementsByTagName("userId");        NodeList pwds=ele.getElementsByTagName("pwd");        if(userIds==null || userIds.getLength()!=1){            throw new Fault(new IllegalArgumentException("用户名格式不对!"));        }        if(pwds==null || pwds.getLength()!=1){            throw new Fault(new IllegalArgumentException("密码格式不对!"));        }        String userId=userIds.item(0).getTextContent();        String pwd=pwds.item(0).getTextContent();        if(!userId.equals("1") ||!pwd.equals("123")){            throw new Fault(new IllegalArgumentException("用户名和密码不对!"));        }    }}

在这个拦截器中,首先判断是SOAP消息中是否有Header,如果有,再判断用户名和密码是否正确。

此时,要将自定义的拦截器添加到InInterceptors,并传入一个Phase的字符串参数。

public class TestMain {    public  static  void main(String[] arg){        HelloWorld hw=new HelloWorldWS();        //hw.sayHi("许晨阳");        EndpointImpl eImpl=(EndpointImpl)Endpoint.publish("http://localhost:9009/HelloWorldWS", hw);        eImpl.getInInterceptors().add(new LoggingInInterceptor());        eImpl.getOutInterceptors().add(new LoggingOutInterceptor());        //自定义拦截器        eImpl.getInInterceptors().add(new AuthInterceptor(Phase.PRE_INVOKE));        System.out.println("Web Service暴露成功!");    }}

此时,如果客户端直接调用,会无法调用。

六月 20, 2016 5:51:24 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log信息: Inbound Message----------------------------ID: 1Response-Code: 500Encoding: UTF-8Content-Type: text/xml;charset=UTF-8Headers: {Content-Length=[222], content-type=[text/xml;charset=UTF-8], Server=[Jetty(7.3.1.v20110307)]}Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>没有Header,不能调用</faultstring></soap:Fault></soap:Body></soap:Envelope>--------------------------------------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.sayHi(Unknown Source)    at com.tgb.ws.ClientMain.main(ClientMain.java:27)    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    at java.lang.reflect.Method.invoke(Method.java:606)    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)Caused by: org.apache.cxf.binding.soap.SoapFault: 没有Header,不能调用

此时返回到客户端的SOAP消息为<soap:Fault>

所以我们要在客户端也添加拦截器将用户名和密码添加到SOAP消息的Header中。

public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {    private String userId;    private String pwd;    public AddHeaderInterceptor(String userId, String pwd) {        super(Phase.PREPARE_SEND);        this.userId=userId;        this.pwd=pwd;    }    @Override    public void handleMessage(SoapMessage soapMessage) throws Fault {        List<Header> headers= soapMessage.getHeaders();        System.out.println(headers.size());        Document doc= DOMUtils.createDocument();        Element ele=doc.createElement("authHeader");        Element eleUser=doc.createElement("userId");        eleUser.setTextContent(userId);        Element elePwd=doc.createElement("pwd");        elePwd.setTextContent(pwd);        ele.appendChild(eleUser);        ele.appendChild(elePwd);        Header header=new Header(new QName("http://impl.ws.tgb.com/"),ele);        headers.add(header);        System.out.println(headers.size());    }}
public class ClientMain {    public static void main(String[] args){        //工厂        HelloWorldWS factory=new HelloWorldWS();        //只是服务的代理        HelloWorld hw=factory.getHelloWorldWSPort();        //客户端拦截器        Client c= ClientProxy.getClient(hw);        c.getInInterceptors().add(new LoggingInInterceptor());        c.getOutInterceptors().add(new AddHeaderInterceptor("1","123"));        c.getOutInterceptors().add(new LoggingOutInterceptor());        System.out.println(hw.sayHi("许晨阳"));    }}

需要注意的是,我们要把此拦截器添加到客户端的OutInterceptors,这个和服务端不一样。

总结

CXF拦截器可以让我们修改SOAP消息,并在此基础上对客户端进行权限控制,很方便。

0 0
原创粉丝点击