当前位置 : 主页 > 网页制作 > Nodejs >

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

来源:互联网 收集:自由互联 发布时间:2021-06-24
背景 当一个服务发布之后,只要有服务地址,我们就可以建立客户端对服务进行调用。如果服务的提供者想要对可以调用服务的客户端进行限制,如:只有某些客户可以调用此服务。这

背景

  当一个服务发布之后,只要有服务地址,我们就可以建立客户端对服务进行调用。如果服务的提供者想要对可以调用服务的客户端进行限制,如:只有某些客户可以调用此服务。这时候就会用到拦截器,来进行权限控制。
  明白了拦截器的应用场景,我们看看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: 3
Address: http://localhost:9009/HelloWorldWS
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {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: 3
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
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: 1
Address: http://localhost:9009/HelloWorldWS
Encoding: UTF-8
Content-Type: text/xml
Headers: {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: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {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: 1
Response-Code: 500
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {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消息,并在此基础上对客户端进行权限控制,很方便。

网友评论