CXF實戰之自定義攔截器(五)

CXF已經內置了一些攔截器,這些攔截器大部分默認添加到攔截器鏈中,有些攔截器也可以手動添加,如手動添加CXF提供的日誌攔截器。也可以自定義攔截器,CXF中實現自定義攔截器很簡單,只要繼承AbstractPhaseInterceptor或者AbstractPhaseInterceptor的子類(如AbstractSoapInterceptor)即可。

自定義權限認證攔截器

權限認證攔截器處理SOAPHeader中的認證信息,客戶端在發起請求時在SOAPHeader中添加認證信息,服務端在接收到請求後,校驗認證信息,校驗通過則繼續執行,校驗不通過則返回錯誤。

<!-- 認證信息格式如下 -->
<auth xmlns="http://www.tmp.com/auth">  
    <name>admin</name>  
    <password>admin</password>  
</auth>

客戶端添加授權攔截器

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;

/**
 * 添加授權攔截器
 * 用於在客戶端發請求時添加授權
 * @author [email protected]
 *
 */
public class AuthAddInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    public AuthAddInterceptor(){
        //準備發送階段
        super(Phase.PREPARE_SEND);
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headers = message.getHeaders();

        Document doc = DOMUtils.createDocument();

        //Element auth = doc.createElement("auth");
        Element auth = doc.createElementNS("http://www.tmp.com/auth", "auth");

        Element name = doc.createElement("name");
        name.setTextContent("admin");

        Element password = doc.createElement("password");  
        password.setTextContent("admin");  

        auth.appendChild(name);  
        auth.appendChild(password);

        headers.add(new Header(new QName(""), auth));
    }
}

服務端授權驗證攔截器

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.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * 服務端輸入攔截器
 * 攔截請求有沒有授權信息
 * @author [email protected]
 *
 */
public class AuthValidateInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    public AuthValidateInterceptor(){
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headers = message.getHeaders();
        if(headers == null || headers.size() < 1) {  
            throw new Fault(new Exception("無授權信息!"));
        }

        Element auth = null;
        //獲取授權信息元素
        for(Header header : headers){
            QName qname = header.getName();
            String ns = qname.getNamespaceURI();
            String tagName = qname.getLocalPart();
            if(ns != null && ns.equals("http://www.tmp.com/auth") && tagName != null && tagName.equals("auth")){
                auth = (Element)header.getObject();
                break;
            }
        }

        //如果授權信息元素不存在,提示錯誤
        if(auth == null){
            throw new Fault(new Exception("無授權信息!"));
        }

        NodeList nameList = auth.getElementsByTagName("name");
        NodeList pwdList = auth.getElementsByTagName("password");
        if(nameList.getLength() != 1 || pwdList.getLength() != 1){
            throw new Fault(new Exception("授權信息錯誤!"));
        }

        String name = nameList.item(0).getTextContent();
        String password = pwdList.item(0).getTextContent();
        if(!"admin".equals(name) || !"admin".equals(password)){
            throw new Fault(new Exception("授權信息錯誤!"));
        }
    }
}

服務端攔截器配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:soap="http://cxf.apache.org/bindings/soap"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd 
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

    <jaxws:endpoint id="helloWSEndpoint" implementor="#helloWS" address="/hello">
        <jaxws:inInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
            <bean class="com.rvho.cxfserver.interceptor.AuthValidateInterceptor"></bean>
        </jaxws:inInterceptors>
        <jaxws:outInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
        </jaxws:outInterceptors>
    </jaxws:endpoint>
</beans>

客戶端請求

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(HelloWS.class);
factory.setAddress("http://localhost:8280/cxfserver/services/hello");

factory.getInInterceptors().add(new org.apache.cxf.interceptor.LoggingInInterceptor());

//客戶端授權攔截器
factory.getOutInterceptors().add(new com.rvho.cxfclient.interceptor.AuthAddInterceptor());
factory.getOutInterceptors().add(new org.apache.cxf.interceptor.LoggingOutInterceptor());

HelloWS helloWS = factory.create(HelloWS.class);
String welcome = helloWS.welcome("[email protected]");

CXF日誌攔截器

CXF提供了輸入日誌攔截器LoggingInInterceptor和輸出日誌攔截器LoggingOutInterceptor,日誌攔截器可以用在服務端也可以用在客戶端。在測試或者調試的時候,可以用日誌攔截器輸出服務端、客戶端請求和接收到的信息。

服務端日誌內容

七月 30, 2015 10:51:37 上午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Inbound Message
----------------------------
ID: 1
Address: http://localhost:8280/cxfserver/services/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive], Content-Length=[212], content-type=[text/xml; charset=UTF-8], host=[localhost:8280], pragma=[no-cache], SOAPAction=[""], user-agent=[Apache CXF 3.1.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>[email protected]</name></ns2:welcome></soap:Body></soap:Envelope>
--------------------------------------

七月 30, 2015 10:51:37 上午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Outbound Message
---------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:welcomeResponse xmlns:ns2="http://www.tmp.com/services/hello"><return>歡迎使用CXF![email protected]</return></ns2:welcomeResponse></soap:Body></soap:Envelope>
--------------------------------------

客戶端日誌內容

七月 30, 2015 10:51:37 上午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Outbound Message
---------------------------
ID: 1
Address: http://localhost:8280/cxfserver/services/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>[email protected]</name></ns2:welcome></soap:Body></soap:Envelope>
--------------------------------------
七月 30, 2015 10:51:37 上午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Inbound Message
----------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Date=[Thu, 30 Jul 2015 02:51:37 GMT], Server=[Apache-Coyote/1.1], transfer-encoding=[chunked]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:welcomeResponse xmlns:ns2="http://www.tmp.com/services/hello"><return>歡迎使用CXF![email protected]</return></ns2:welcomeResponse></soap:Body></soap:Envelope>
--------------------------------------
歡迎使用CXF![email protected]
發佈了91 篇原創文章 · 獲贊 40 · 訪問量 86萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章