1. 程式人生 > >CXF動態客戶端呼叫JDK自帶Webservice安全校驗

CXF動態客戶端呼叫JDK自帶Webservice安全校驗

        專案中有個需求,需要使用CXF動態客戶端呼叫webservice服務端,這個服務端是JDK自帶的webservice釋出的,而且我們需要在呼叫時傳入使用者名稱和密碼。網上CXF客戶端和服務端配套使用webservice的方法很多,這裡不再贅述,這裡主要講下我上邊說的特殊使用方式。有人會把使用者名稱和密碼放在webservice的請求引數裡,這樣汙染了webservice介面,本人不喜歡這種方式。

        開始的時候,我先試了CXF攔截器傳送密碼的方式,我自己是參照類似的文章寫的:點選開啟連結,結果發現出現很多奇怪的錯誤,比如各種名稱空間不識別,JAXB解組錯誤等等,壓根就沒有進入服務端的handler,當然了服務端的總入口也是拿到了請求,只是在進入handler之前就報錯了。按說CXF也是遵守了webservice的國際規範了應該可以的。後來看了CXF中的傳入使用者名稱和密碼所涉及的類和引數,分析出CXF應該是對SOAP的head操作做了封裝,所以導致SOAP中的具體資料內容和JDK自帶的webservice是不同的,怎麼辦呢?後來想到我可以直接自定義SOAP頭,然後到服務端的handler中拿到這個頭進行分析不就解決了?經過各種除錯,終於解決了。下邊公佈程式碼:

        1、服務端的handlers.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
             <handler-chain>
               <handler>
                  <handler-name>ServiceSOAPHandler</handler-name>
                  <handler-class>com.cms.webservice.AuthorityHandler</handler-class>
              </handler>
            </handler-chain>
            </handler-chains>

       2、服務端的handler程式碼:

    /**
     * 
     */
    package com.cms.webservice;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.Set;
    
    import javax.xml.namespace.QName;
    import javax.xml.soap.Node;
    import javax.xml.soap.SOAPBody;
    import javax.xml.soap.SOAPConstants;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPFault;
    import javax.xml.soap.SOAPHeader;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    import javax.xml.ws.soap.SOAPFaultException;
    
    import com.jeecms.cms.Constants;
    import com.jeecms.common.util.PropertyUtils;
    
    /**
     * 服務端許可權校驗類
     * 
     * @author zhaichong
     *
     *         2014年10月1日
     */
    public class AuthorityHandler implements SOAPHandler<SOAPMessageContext> {
    
    private static String PROPERTIE_NAME="webservice.properties";
    private static String USER_NAME_PWD="webservice.userNamePwd";
   
    public boolean handleMessage(SOAPMessageContext context) {
    return auth(context);
    }
    
    /**
    * 校驗使用者名稱密碼是否合法
    * 
    * @param context
    * @return
    */
    private boolean auth(SOAPMessageContext context) {
    Boolean out = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if (!out) {
    SOAPMessage message = context.getMessage();
    try {
    SOAPHeader header = message.getSOAPPart().getEnvelope().getHeader();
    if (header != null) {
    // 獲取SOAP頭登入校驗節點
    // org.w3c.dom.Node node =
    // header.getElementsByTagName("authHeader").item(0);
    // 獲取使用者名稱
    org.w3c.dom.Node userNameNode = header.getElementsByTagName("userName").item(0);
    String userName = userNameNode.getTextContent();
    // 獲取密碼
    org.w3c.dom.Node passwordNode = header.getElementsByTagName("password").item(0);
    String password = passwordNode.getTextContent();
    // 獲取本地配置檔案使用者名稱密碼 與傳過來的使用者名稱密碼比對
    PropertiesUtil propertiesUtil = new PropertiesUtil(PROPERTIE_NAME);
    String userNamePWD = propertiesUtil.getKeyValue(USER_NAME_PWD);
    if (userNamePWD != null) {
    String namePWDs[] = userNamePWD.split(",");
    for (int i = 0; i < namePWDs.length; i++) {
    if (namePWDs[i] != null) {
    String uName = namePWDs[i].split("\\|")[0];
    String uPassword = namePWDs[i].split("\\|")[1];
   
    if (uPassword.equals(password) && uName.equals(userName)) {
    return true;
    }
    }
    }
    }
    //System.out.println("client send userName:" + userName);
    //System.out.println("client send password:" + password);
    return false;
    } else {
    return false;
    }
    } catch (SOAPException e) {
    e.printStackTrace();
    }
    
    }
    
    return true;
    }
    
    public boolean handleFault(SOAPMessageContext context) {
    // TODO Auto-generated method stub
    return false;
    }
    
    public void close(MessageContext context) {
    // TODO Auto-generated method stub
    
    }
    
    public Set<QName> getHeaders() {
    // TODO Auto-generated method stub
    return null;
    }
    
    }

   注意: 這裡的handler.xml檔案在war包裡是放在classes下的,webservice的實現類要用@HandlerChain(file="handlers.xml")進行註解,上邊程式碼的使用者名稱和密碼是放在properties檔案中的,各位網友可以自己修改。

3、客戶端的攔截器:

    package gboat2.cxf.test;


    import gboat2.cxf.utils.AuthorityParameter;
    
    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;
    
    /**
     * <p>
     * 呼叫webservice時需要傳入使用者名稱和密碼
     * </p>
     *
     */
    public class AuthorityHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage>{  
        private AuthorityParameter authorityParameter;
        public AuthorityHeaderInterceptor(AuthorityParameter authorityParameter) {  
            super(Phase.PREPARE_SEND);  
            this.authorityParameter = authorityParameter;
        }   
        
        public void handleMessage(SoapMessage msg) throws Fault {    
            List<Header> headers = msg.getHeaders();  
            //建立Document物件  
            Document doc = DOMUtils.createDocument();  
    
            //配置伺服器端Head資訊的使用者密碼  
            Element eleId= doc.createElement(this.authorityParameter.getUserNameKey());  
            eleId.setTextContent(this.authorityParameter.getUserNameValue());  
            Element elePass = doc.createElement(this.authorityParameter.getPasswordKey());  
            elePass.setTextContent(this.authorityParameter.getPasswordValue());   
            /** 
             * 也可以先建立一個父節點,則生成的XML文件 ,我們這裡是直接使用使用者名稱和密碼
             * <authHeader> 
             *      <userId>lzw</userId> 
             *      <userPass>123456</userPass> 
             * </authHeader> 
             */  
            headers.add(new Header(new QName(""), eleId));  
            headers.add(new Header(new QName(""), elePass)); 
        }   
    }  

    4、使用者名稱和密碼類:

        
    package gboat2.cxf.utils;
    
    
    public class AuthorityParameter {
    /**
    * 使用者名稱欄位的名稱
    */
    private String userNameKey;
   
    /**
    * 使用者名稱欄位的值
    */
    private String userNameValue;
   
    /**
    * 密碼欄位的名稱
    */
    private String passwordKey;
   
    /**
    * 密碼欄位的值
    */
    private String passwordValue;
   
    public AuthorityParameter() {
    super();
    }
   
    /**  
    * AuthorityParameter
    * @param userNameKey 使用者名稱的欄位名稱
    * @param userNameValue 使用者名稱的欄位值
    * @param passwordKey 密碼的欄位名稱
    * @param passwordValue 密碼的欄位值
    */
    public AuthorityParameter(String userNameKey, String userNameValue, String passwordKey, String passwordValue) {
    super();
    this.userNameKey = userNameKey;
    this.userNameValue = userNameValue;
    this.passwordKey = passwordKey;
    this.passwordValue = passwordValue;
    }
    
    public String getUserNameKey() {
    return userNameKey;
    }
    
    public void setUserNameKey(String userNameKey) {
    this.userNameKey = userNameKey;
    }
    
    public String getUserNameValue() {
return userNameValue;
}


public void setUserNameValue(String userNameValue) {
this.userNameValue = userNameValue;
}


public String getPasswordKey() {
return passwordKey;
}


public void setPasswordKey(String passwordKey) {
this.passwordKey = passwordKey;
}


public String getPasswordValue() {
return passwordValue;
}


public void setPasswordValue(String passwordValue) {
this.passwordValue = passwordValue;
}
   }

    5、呼叫程式碼

   JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); 
   Client client = null; 
   // 建立客戶端連線 
   client = factory.createClient("http://localhost:9090/cms/saveCms?wsdl"); 

   AuthorityParameter param = new AuthorityParameter("userName", "anshun", "password", "123456");
   client.getOutInterceptors().add(new AuthorityHeaderInterceptor(authorityParameter)); 
   client.getOutInterceptors().add(new LoggingOutInterceptor()); 

   // 客戶端設定

   HTTPClientPolicy policy = ((HTTPConduit) client.getConduit()).getClient();
   policy.setConnectionTimeout(30000);
   policy.setReceiveTimeout(180000);

   // 以下就是具體呼叫方法,這裡不寫了,網上很多。

   ......

   好了,這樣在服務端就能獲取到使用者名稱和密碼,又不會汙染webservice的方法引數。記下來防止遺忘,也為各位網友解決這種問題提供個思路,網上這種資料太少了。其中的部分程式碼是從專案程式碼裡摘錄出來的,可能有的地方有紕漏,但是思路脈絡已經清除了,希望能幫到各位網友。另外,如果有需要了解JDK自帶webservice如何使用使用者名稱和密碼來進行呼叫前的校驗,可以參考我的一個例子:點選開啟連結

相關推薦

CXF動態客戶呼叫JDKWebservice全校

        專案中有個需求,需要使用CXF動態客戶端呼叫webservice服務端,這個服務端是JDK自帶的webservice釋出的,而且我們需要在呼叫時傳入使用者名稱和密碼。網上CXF客戶端和服務端配套使用webservice的方法很多,這裡不再贅述,這裡主要講下我

CXF動態客戶呼叫webservice例項

使用CXF實現WebService,並在客戶端實現動態呼叫編寫伺服器注意事項 注意 :不要指定 @SOAPBinding(style=Style.RPC, use=Use.LITERAL) 因為cxf 不支援:rpc、encoded,在動態客戶呼叫過程。 cxf w

cxf 生成客戶呼叫測試用例

使用步驟如下: 一、下載apache cxf的包,如apache-cxf-2.7.10.zip,地址:cxf.apache.org/download.html 二、解壓apache-cxf-2.7.10.zip至某一目錄,如D:\apache-cxf-2.7.10 三、設定環境變數 1、CXF_HOM

zabbix監控客戶mysql用的模板

Zabbix3.0 Server以後就自帶了MySQL外掛來監控mysql資料庫的模板,只需要配置好agent客戶端,然後在web端給主機增加模板就行了。  以下是公司線上的zabbix3.0環境下新增mysql監控操作記錄: Zabbix_agent客戶端操作1)首先在客戶端的mysql裡新增許可權,即

CXF 動態客戶--複雜物件

      大家都知道,CXF提供了兩種建立客戶端的方式:一種是使用cxf提供的wsdl2java命令生成客戶端,另一種就是動態建立客戶端。關於第一種方式,就是直接將遠端提供的類資訊在本地生成,原理很簡單。關鍵是動態呼叫並且方法引數為複雜物件時,這種方式是通過動態載入(載入到

編寫ftp客戶連線linuxftp服務vsftpd中遇到的問題

背景知識:           vsftpd:是linux自動的ftp伺服器。          檢視狀態 service vsftpd status, 啟動:service vsftpd start 停止:service vsftpd stop          配置檔案

服務使用CXF框架客戶使用Axis2框架的webservice實現方案

背景:       執行在兩臺獨立伺服器上的兩個web服務,其中一個web服務需要訪問另一個web服務的業務方法。但是兩個服務各自的執行環境不同,一個服務執行在jdk1.5上(服務端),使用spring2.5.6框架管理bean,而另一個執行在jdk1.4環境下(客戶端)。現

CXF客戶呼叫--HelloWorld!

CXF通過執行時代理生成遠端服務的代理物件,在客戶端完成對webservice的訪問 package com.flyfox.client; import org.apache.cxf.endpoint.Client; import org.apache.cxf.

SpringBoot整合cxf釋出WebService服務和客戶呼叫WebService服務

最近在做公司專案的一個功能需要寫WebSerice介面,為了系統得學習WebService,決定寫一個測試介面的例子。 測試專案中使用的是SpringBoot(spring整合cxf需新增cxf-rt-frontend-jaxws,cxf-rt-transpo

CXF的三種釋出方式和客戶呼叫方法

先定義一個web service @WebService(targetNamespace="http://www.itfad.net/queryUser") public interface IQueryUser { String query(@WebParam(nam

利用wsdl地址生成java客戶呼叫類並實現動態配置的方法

前言:        有時,我們經常要和一些外部系統對接,如果是HTTP介面還好,直接用apache的HttpClient工具類呼叫即可。而如果對方系統是Webservice,則比較麻煩,本文主要講解如何用對方的wsdl地址生成java客戶端呼叫類並且動態配置訪問地址並在ja

通過cxf JaxWsDynamicClientFactory進行WebService 客戶呼叫

通過JaxWsDynamicClientFactory進行WebService 客戶端呼叫的一個好處就是隻需要知道了WSDL地址就行了,不需要手動生成任何程式碼,這樣,如果需要呼叫多個WebService服務的話,只需要建立多個Client即可,不用考慮傳統方式(生成程式碼)

SpringBoot | CXF釋出WebService服務和客戶呼叫WebService服務

一、引入maven依賴 <!-- cxf支援 --> <dependency> <groupId>org.apache.cxf</groupId> <art

JDK動態代理Proxy類和InvocationHandler介面

package yq.com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DaoProxy i

jdk annotation釋出webservice服務 及生成客戶呼叫程式碼

下面我們簡要介紹如何通過jdk自帶的註解釋出webservice 首先新建一個Java project為jdkmodel_server (1)釋出服務 第一步:新建需要釋出的介面HelloWorld.java,裡面包含一個sayHello方法,其次寫出這個介面的實現類實現

死鎖排查的小竅門 --使用jdk管理工具jstack

pre ble new deadlock 一段 指令 tro bject print 本文版權歸 遠方的風lyh和博客園共有,歡迎轉載,但須保留此段聲明,並給出原文鏈接,謝謝合作。 開發時間久了,難免會寫出一些一些死鎖的代碼,自己明明調用該方法可該方法就是不執行、不進該

使用JDK的JConsole性能調優

post catalina maxperm max 分享圖片 前行 性能調優 保存 style 找到你安裝的JDK運行此exe文件 如圖所示你會看到此界面 接下來運行你的tomcat但是再次之前我們需要加點東西 如圖中找到bin目錄下的catalin

JDK的jvisualvm安裝Visual GC插件

plugins 點擊下載 png 鏈接 cmd pan 自帶 ron 點擊 1.打開cmd,輸入jvisualvm,回車; 2.點擊工具——>插件; 3.訪問網址:https://visualvm.github.io/pluginscenters.html,找到

利用JDK的keytool生成SSL證書然後導入到SpringBoot

生成 密鑰 clas alias 自帶 就會 輸入 http -type 一:生成命令如下(這一步生成的暫不知道幹嘛用的) E:\Desktop\Documents\證書>keytool -genkey -alias tomcat -keypass 123456

使用jdk的visualVM監控遠程監控was

tps root fin 監控 sina xmx nag 結束進程 requested 1.登錄was控制臺https://172.16.87.221:9043/ibm/console/unsecureLogon.jsp服務器--服務器類型--Java 和進程管理---