大夢想家

          5年開發(fā)工程師,2年實(shí)施經(jīng)理,X年售前顧問,......
          數(shù)據(jù)加載中……
          RCP實(shí)踐之安全模型
              感謝大家最近對本系列的關(guān)注和評論,我會繼續(xù)完善內(nèi)容,并且總結(jié)教訓(xùn)寫出更好的東東來。
              今天談?wù)勛罱谘芯康腞CP安全模型,其實(shí)RCP在誕生之初就是建立在一個非常魯棒的框架之上的---OSGi,它不但有全新的概念,全新的思路,全新的熱插拔技術(shù),還有非常好的安全模型(equinox security 項(xiàng)目好像還在孵化中) 。

              解決RCP的安全問題,從最近的調(diào)研中看是有四種方式:
          1.equinox security項(xiàng)目;
          2.使用org.eclipse.ui.activities擴(kuò)展點(diǎn)定義可訪問權(quán)限和角色;
          3.使用Eclipse-JAAS插件;
          4.自己寫代碼在對功能點(diǎn)進(jìn)行過濾;

             第一種方案不可行,因?yàn)閑quinox security項(xiàng)目還在孵化中,而且沒有充足的文檔,因此放棄;
             第二種方案可行,但是靈活性不夠,我們很難在項(xiàng)目開始之初充分的定義出所有的角色以及角色對應(yīng)的權(quán)限,而且還要引入大量的配置,所以也放棄;
             第三種方案可能可行,因?yàn)閺睦贤獾奈臋n中看出,這個插件是可用的,而且是強(qiáng)大的,它的原理就是定義了一堆自己的擴(kuò)展點(diǎn),然后通過分析擴(kuò)展點(diǎn),過濾掉不可用的功能點(diǎn)。但是這個插件的更新時(shí)間竟然是2005年,N久都沒有人管過了~而且還是基于Eclipse3.0的實(shí)現(xiàn),所以也放棄了;
              我選擇的是第四種方案,自己寫代碼對功能點(diǎn)進(jìn)行過濾,其實(shí)思路很簡單,我們定義基類,在基類中過濾掉有那些功能點(diǎn)可以被顯示,或者不能被顯示。
              RCP應(yīng)用中所需要關(guān)注安全點(diǎn)主要是:
          1.Action
          2.Viewer
          3.編輯器
          4.透視圖
              經(jīng)過討論,其實(shí)我們的關(guān)注點(diǎn)主要集中在Action和透視圖,因?yàn)橥敢晥D總會包含一組Viewer出現(xiàn)所以我們只要在透視圖布局類中將我們不需要關(guān)注的Viewer過濾掉,那么Viewer就可以被管理起來了,而編輯器的出現(xiàn)也主要是針對Viewer出現(xiàn)的,如果一個Viewer不能顯示,那么和它對應(yīng)的編輯器也永遠(yuǎn)無法顯示,所以編輯器幾乎不用考慮。
             其實(shí)安全模型的核心就是Action,Viewer,透視圖。
             對于Action,存在兩種,一種是開發(fā)人員自己在代碼中創(chuàng)建出來的Action(new Action),另一種就是在plugin.xml中配置的。
            第一種情況的基類:
           1package com.glnpu.dmp.client.platform.core.internal.security.absaction;
           2
           3import org.apache.log4j.Logger;
           4import org.eclipse.jface.action.Action;
           5import org.eclipse.jface.resource.ImageDescriptor;
           6
           7import com.glnpu.dmp.client.platform.core.internal.security.SecurityManager;
           8
           9/**
          10 * 繼承自<code>Action</code>,在構(gòu)造方法中加入用戶權(quán)限判斷。
          11 * @author lign
          12 *
          13 */

          14public abstract class AbstractSecurityAction extends Action {
          15    private Logger log = Logger.getLogger(this.getClass());
          16    
          17    public AbstractSecurityAction(String text, ImageDescriptor image){
          18        super(text, image);
          19        this.setActionId();
          20        log.debug("當(dāng)前處理的Action為: " + this.getId());
          21        //權(quán)限判斷
          22        SecurityManager.securityFiltration(this);
          23    }

          24    /**
          25     * 實(shí)現(xiàn)者必須實(shí)現(xiàn)此方法,并在方法內(nèi)調(diào)用setId方法,為Action命名。
          26     */

          27    public abstract void setActionId();
          28}
          開發(fā)人員自己創(chuàng)建的Action都繼承自AbstractSecurityAction類,在此類的構(gòu)造方法中,調(diào)用SecurityManager.securityFiltration(this);方法,判斷當(dāng)前Action的ID是否與當(dāng)前用戶權(quán)限的中的ID相同,如果相同則調(diào)用action.setEnabled(true);,否則則是action.setEnabled(false);
              /**
               * 通過傳入的IAction實(shí)例的id,判斷是否與用戶對應(yīng)的權(quán)限相同,如果存在與用戶權(quán)限中,則此IAction為可視,否則為不可視。
               * 
          @param action
               
          */

              
          public static void securityFiltration(IAction action){
                  
          if(action!=null{
                      action.setEnabled(
          false);
                      
          if(action.getId()!=null && !action.getId().equals("")) {
                          log.debug(
          "當(dāng)前處理的Action為 : " + action.getId() + " 當(dāng)前用戶可用Action列表長度為 :" + UserInfo.getInstance().getActionList().size());
                          
          for(String str : UserInfo.getInstance().getActionList()) {
                              
          if(str.equals(action.getId())) {
                                  action.setEnabled(
          true);
                                  log.debug(
          "當(dāng)前Action : " + action.getId() + "與用戶可用Action列表中Action匹配,此Action可顯示");
                                  
          return;
                              }

                          }

                      }

                  }

              }

             第二種情況的基類:
           1package com.glnpu.dmp.client.platform.core.internal.security.absaction;
           2
           3import org.eclipse.jface.action.IAction;
           4import org.eclipse.jface.viewers.ISelection;
           5import org.eclipse.ui.IEditorActionDelegate;
           6import org.eclipse.ui.IEditorPart;
           7
           8import com.glnpu.dmp.client.platform.core.internal.security.SecurityManager;
           9
          10/**
          11 * 實(shí)現(xiàn)自<code>IEditorActionDelegate</code>重載selectionChanged方法,在其中加入用戶權(quán)限判斷。
          12 * @author lign
          13 *
          14 */

          15public abstract class AbstractSecurityEditorActionDelegate implements IEditorActionDelegate {
          16
          17    /* (non-Javadoc)
          18     * @see org.eclipse.ui.IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, org.eclipse.ui.IEditorPart)
          19     */

          20    public abstract void setActiveEditor(IAction action, IEditorPart targetEditor);
          21
          22    /* (non-Javadoc)
          23     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
          24     */

          25    public abstract void run(IAction action);
          26
          27    /* 
          28     * 重載方法,加入權(quán)限判斷重置Action是否可用
          29     */

          30    public void selectionChanged(IAction action, ISelection selection) {
          31        //判斷權(quán)限
          32        SecurityManager.securityFiltration(action);
          33    }

          34
          35}
          以上是擴(kuò)展editorAction擴(kuò)展點(diǎn)時(shí)要繼承的基類,其他兩種情況同它相同。
             這種方法雖然笨拙,但是還是有用的。
             Viewer的顯示總是依靠某一個透視圖的,因此就有了我們的透視圖基類:
           1package com.glnpu.dmp.client.platform.core.internal.security.absperspective;
           2
           3import java.util.ArrayList;
           4import java.util.List;
           5
           6import org.apache.log4j.Logger;
           7import org.eclipse.ui.IFolderLayout;
           8import org.eclipse.ui.IPageLayout;
           9import org.eclipse.ui.IPerspectiveFactory;
          10
          11import com.glnpu.dmp.client.platform.core.internal.security.SecurityManager;
          12
          13/**
          14 * 實(shí)現(xiàn)自<code>IPerspectiveFactory</code>,提供標(biāo)準(zhǔn)布局,及左側(cè)為Viewers,底部為Viewers
          15 * @author lign
          16 *
          17 */

          18public abstract class AbstractSecurityPerspective implements IPerspectiveFactory {
          19    
          20    private Logger log = Logger.getLogger(this.getClass());
          21    
          22    protected String [] leftViewerIds = null;
          23    protected String [] bottomViewerIds = null;
          24    protected String perspectiveName = null;
          25    
          26    /* (non-Javadoc)
          27     * @see org.eclipse.ui.IPerspectiveFactory#createInitialLayout(org.eclipse.ui.IPageLayout)
          28     */

          29    public void createInitialLayout(IPageLayout layout) {
          30        List<String> leftViewerList = getLeftViewers(leftViewerIds);
          31        log.debug("當(dāng)前用戶可用的leftViewer列表長度為 : " + leftViewerList.size());
          32        if(leftViewerList.size()>0{
          33            IFolderLayout folderLayoutLeft = layout.createFolder(this.perspectiveName+"Left", IPageLayout.LEFT, 0.25f, layout.getEditorArea()); 
          34            for(String str : leftViewerList) {
          35                folderLayoutLeft.addView(str);
          36                layout.getViewLayout(str).setCloseable(false);
          37            }

          38        }

          39
          40        List<String> bottomViewerList = getBottomViewers(bottomViewerIds);
          41        log.debug("當(dāng)前用戶可用的bottomViewer列表長度為 : " + bottomViewerList.size());
          42        if(bottomViewerList.size()>0{
          43            IFolderLayout folderLayoutBottom = layout.createFolder(this.perspectiveName+"Bottom", IPageLayout.BOTTOM, 0.80f, layout.getEditorArea()); 
          44            for(String str : bottomViewerList) {
          45                folderLayoutBottom.addView(str);
          46                layout.getViewLayout(str).setCloseable(false);
          47            }

          48        }

          49    }

          50    
          51    /**
          52     * 過濾不可顯示的左側(cè)Viewer
          53     * @param leftViewerIds
          54     * @return
          55     */

          56    private List<String> getLeftViewers(String [] leftViewerIds) {
          57        List<String> _list = new ArrayList<String>();
          58        for(String str : leftViewerIds) {
          59            if(SecurityManager.isSecurityViewer(str)) {
          60                _list.add(str);
          61            }

          62        }

          63        return _list;
          64    }

          65    
          66    /**
          67     * 過濾不可顯示的底部Viewer
          68     * @param bottomViewerIds
          69     * @return
          70     */

          71    private List<String> getBottomViewers(String [] bottomViewerIds) {
          72        List<String> _list = new ArrayList<String>();
          73        for(String str : bottomViewerIds) {
          74            if(SecurityManager.isSecurityViewer(str)) {
          75                _list.add(str);
          76            }

          77        }

          78        return _list;
          79    }

          80}
          其子類需要在構(gòu)造方法中給父類的leftViewerIds,bottomViewerIds和perspectiveName屬性付值,及傳給父類左側(cè)需要放置那些Viewer的ID,底部需要放置那些Viewer的ID,剩下的就是過濾了。
             其實(shí)最麻煩的是過濾透視圖,透視圖是必須配置到plugin.xml中的,只要配置進(jìn)去,我們基本上就不能做什么操作了,在透視圖的菜單中有Other...項(xiàng),會列出所有的透視圖。我們的解決辦法是:
           1    /**
           2     * 在RCP程序的ApplicationWorkbenchWindowAdvisor類的postWindowCreate()方法中調(diào)用,用于刪除無權(quán)限操作的Perspective
           3     * @param pr
           4     */

           5    public static void perspectiveFiltration(PerspectiveRegistry pr) {
           6        IPerspectiveDescriptor[] _ipd = pr.getPerspectives();
           7        Object [] _objs = new Object[_ipd.length];
           8        for(int i=0; i<_ipd.length; i++{
           9            if(!isSecurityPerspective(_ipd[i].getId())) {
          10                _objs[i] = _ipd[i];
          11            }

          12        }

          13        log.debug("從已注冊的Perspective列表中刪除Perspectives為: " + _objs.toString());
          14        pr.removeExtension(null, _objs);
          15        log.debug("需要重新注冊新的默認(rèn)Perspective頁");
          16        setDefautlPerspectice(pr);
          17    }
          取得透視圖注冊器,然后移除不可用的擴(kuò)展點(diǎn)。但是Eclipse在移除擴(kuò)展點(diǎn)時(shí)有一個BUG會彈出一個錯誤對話框,但是移除擴(kuò)展點(diǎn)的代碼照樣執(zhí)行,至少在3.2.2中這個BUG是存在的,而且在Eclipse的BUG管理器中,這個BUG已經(jīng)提出來了,聽說是正在修復(fù)。沒關(guān)系,還好它是開源的,到最后產(chǎn)品發(fā)布的時(shí)候它還沒有修改,我們就自己改了。
             到此,安全文件就這樣解決了,希望大家說說自己的看法,肯定有比我更好的辦法解決,不妨貢獻(xiàn)出來,我們互相學(xué)習(xí)。


          客戶虐我千百遍,我待客戶如初戀!

          posted on 2007-06-21 21:52 阿南 閱讀(2082) 評論(5)  編輯  收藏 所屬分類: Eclipse-RCP西安java用戶群

          評論

          # re: RCP實(shí)踐之安全模型 2007-06-22 14:05 SoulEngineer

          好!基本上和我思路一樣,不過可以自己嘗試著加入JAAS的內(nèi)容,這個必竟是SUN官方的東西
            回復(fù)  更多評論    

          # re: RCP實(shí)踐之安全模型 2007-06-24 21:43 阿南

          好消息,Eclipse3.3已經(jīng)修正了那個BUG了~
            回復(fù)  更多評論    

          # re: RCP實(shí)踐之安全模型 2007-07-28 10:11 SoulEngineer

          現(xiàn)在在想,如果能把安全模型做到無侵入就好了
            回復(fù)  更多評論    

          # re: RCP實(shí)踐之安全模型 2008-10-06 22:30 CHENZHY

          最近也一直在擺弄這個東西,關(guān)于權(quán)限控制總是不得要領(lǐng),版主要是能發(fā)個比較全一些的模型就好了,謝謝了。zhongyu-chen@163.com
          不勝感激!
            回復(fù)  更多評論    

          # re: RCP實(shí)踐之安全模型 2009-07-06 13:40 單飛

          呵呵,最好能夠封裝成為一個無侵入的插件.統(tǒng)一對Action和View/Editor進(jìn)行管理,或者使用Perspective也不錯哦.
            回復(fù)  更多評論    
          主站蜘蛛池模板: 台安县| 镇巴县| 镇远县| 仁布县| 抚顺市| 张家界市| 景谷| 南平市| 安多县| 南安市| 光泽县| 运城市| 南皮县| 西吉县| 永春县| 元朗区| 大邑县| 绥中县| 德兴市| 五家渠市| 绵阳市| 碌曲县| 永丰县| 连州市| 南开区| 新蔡县| 平江县| 吉木乃县| 县级市| 聂拉木县| 台湾省| 白山市| 新巴尔虎左旗| 东莞市| 凭祥市| 安丘市| 讷河市| 武清区| 华宁县| 泰和县| 酉阳|