1. 程式人生 > >dubbo介面訪問控制 - 白名單

dubbo介面訪問控制 - 白名單

      微服務背景下,一個web應用都可能不再service依賴,而是通過RPC呼叫遠端伺服器上的服務。這些服務裡,就包括了一些不能輕易暴露的後臺功能介面。暴露出去的dubbo介面註冊到某一個zk上後,該dubbo介面對註冊到該zk上的消費者都是可見的。對公司內部而言,通常不會有人蓄意去呼叫一些敏感的介面,但也存在人為誤用的可能呀。為此,考慮通過白名單機制來控制dubbo介面的訪問。

現在以許可ip127.0.0.1訪問介面fundRecordTemplateFacade為例演示。

擴充套件Filter

首先,我們需要實現com.alibaba.dubbo.rpc.Filter介面:

@Activate(group = { Constants.CONSUMER, Constants.PROVIDER })
public class FacadeAccessFilter implements Filter {

    private FacadeAccessConfig facadeAccessConfig;

    public FacadeAccessConfig getFacadeAccessConfig() {
        return facadeAccessConfig;
    }

    // 通過setter方式注入白名單配置檔案
    public
void setFacadeAccessConfig(FacadeAccessConfig facadeAccessConfig) { this.facadeAccessConfig = facadeAccessConfig; } @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { Result result = null; // 獲取呼叫的介面名 String reqFacade = invoker.getInterface().getSimpleName(); try
{ // 嘗試在白名單配置檔案裡查詢定義的介面,如果找不到則catch住異常、並許可訪問。 Method method; try { method = facadeAccessConfig.getClass().getDeclaredMethod(editMethodName(reqFacade)); } catch (NoSuchMethodException e) { // 無特殊限制,則許可訪問 result = invoker.invoke(invocation); return result; } // 走到這裡,說明白名單配置檔案配了對該facade的訪問限制 // 獲取remoteAddress:進行訪問的應用,格式ip:port String remoteAddress = RpcContext.getContext().getRemoteAddressString(); // 只取ip String remoteIp = remoteAddress.split(":")[0]; // 獲取licensinedApplications:許可的應用列表 String licensinedApplications = (String) method.invoke(facadeAccessConfig); if (StringUtils.isNotEmpty(licensinedApplications) && StringUtils.isNotEmpty(remoteIp) && licensinedApplications.contains(remoteIp)) { // 許可權許可、進行訪問 Help.log_info(getClass(), " remoteAddress" + remoteAddress + "訪問介面" + reqFacade); result = invoker.invoke(invocation); return result; } else { // 許可權不許可、退出訪問 Help.log_info(getClass(), " remoteAddress" + remoteAddress + "無權訪問介面" + reqFacade); result = new RpcResult("remoteAddress" + remoteAddress + "無權訪問介面" + reqFacade); return result; } } catch (SecurityException e) { Help.log_error(getClass(), "校驗remoteAddress是否有許可權訪問" + reqFacade + "發生異常", e); } catch (IllegalAccessException e) { Help.log_error(getClass(), "校驗remoteAddress是否有許可權訪問" + reqFacade + "發生異常", e); } catch (IllegalArgumentException e) { Help.log_error(getClass(), "校驗remoteAddress是否有許可權訪問" + reqFacade + "發生異常", e); } catch (InvocationTargetException e) { Help.log_error(getClass(), "校驗remoteAddress是否有許可權訪問" + reqFacade + "發生異常", e); } return result; } private String editMethodName(String fieldName) { return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length()); } }

    配置檔案

    1. 在resources目錄下新增純文字檔案META-INF/dubbo/com.alibaba.dubbo.rpc.Filter,內容如下:
      這裡寫圖片描述

    2. 修改配置檔案dubbo-common.xml,在dubbo:provider屬性中新增配置的filter,內容如下:
      在dubbo:provider中新增配置的filter

    3. 擴充套件Filter時,我們是通過setter方法將訪問白名單FacadeAccessConfig註冊到FacadeAccessFilter類中的,那麼在配置檔案(譬如:applicationContext.xml)裡還需要對bean例項化。

        <!-- 將facade訪問白名單註冊到FacadeAccessFilter類中 -->
        <bean id="facadeAccessFilter" class="com.roger.account.provider.filter.FacadeAccessFilter">
            <property name="facadeAccessConfig" ref="facadeAccessConfig" />
        </bean>
        <bean id="facadeAccessConfig" class="com.roger.account.provider.filter.FacadeAccessConfig" />
      

      訪問白名單檔案

      我們看一下白名單檔案的設計格式。本意希望能配置成”介面名=呼叫介面的應用名”,因為部署應用的ip變化可能性遠高於應用本身的名稱修改。但是在Invoker和Invocation物件中找不到客戶端的應用名,無奈之下,就設計成了”介面名=呼叫介面的ip”。
      白名單

      下面是FacadeAccessConfig類,定義的私有屬性都是需要控制權限的dubbo介面名,getter方法從配置平臺disconf上找到對應配置檔案的對應屬性值。

      @Component(value = "facadeAccessConfig")
      @DisconfFile(filename = "facadeAccessConfig.properties")
      public class FacadeAccessConfig {
      
          // 定義可以訪問fundRecordTemplateFacade的應用
          private String fundRecordTemplateFacade;
      
          @DisconfFileItem(associateField = "fundRecordTemplateFacade", name = "fundRecordTemplateFacade")
          public String getFundRecordTemplateFacade() {
              return fundRecordTemplateFacade;
          }
      
          public void setFundRecordTemplateFacade(String fundRecordTemplateFacade) {
              this.fundRecordTemplateFacade = fundRecordTemplateFacade;
          }
      
      }
        

        這樣,對於已經配置的一個介面,新增可訪問的應用只需要新增ip。對於一個新配置的介面,只需要在配置檔案facadeAccessConfig.properties裡新增”介面名=呼叫介面的應用名”,然後在FacadeAccessConfig類中新增私有屬性即可。

        本部落格為轉載文章,如有侵權請及時聯絡。
        原部落格連結:http://blog.csdn.net/peerless_hero/article/details/72667550