天天看點

【開源架構】EFW架構中的系統權限與頁面子權限詳解

 回《【開源】EFW架構系列文章索引》       

 EFW架構源代碼下載下傳V1.3:http://pan.baidu.com/s/1c0dADO0

 EFW架構執行個體源代碼下載下傳:http://pan.baidu.com/s/1eQCc69G

使用EFW架構開發系統,架構中提供了兩個級别的權限控制:角色菜單權限與頁面子權限。

      角色菜單權限:就是不同的使用者登入系統後,根據配置的權限動态生成的菜單,管理者一般全部菜單都可以看到,而一般使用者很多菜單就看不到;使用者綁定角色,角色配置系統菜單,系統根據登入的使用者先查找綁定的角色,再根據角色查找配置的菜單,然後将菜單顯示架構中;角色放在使用者與菜單之間,主要就是簡化使用者的配置;如果沒有角色,給每個使用者配置菜單,那配置得有多麻煩;

      頁面子權限:一般來說權限達到菜單級别就能滿足大部分情況,而有些系統或功能對權限控制要求更細,需要達到頁面中功能也要能夠加入權限配置;為了滿足這種需求,EFW架構提供了頁面子權限的功能,當然配置起來比菜單級的肯定要複雜些;先維護好每個頁面的子權限清單,再配置好每個角色與頁面子權限清單的關系,然後打開頁面的時候,根據頁面與使用者就可以查出配置頁面子權限,根據這個配置資訊界面需要進行額外編碼完成界面上不同權限的操作;

見下圖:頁面子權限的效果圖

給執行個體中的“書籍管理”界面設定頁面子權限,給界面的“新增”、“儲存”和“導出”三個功能按鈕配置權限控制;

圖中上面兩個界面,前一個頁面子權限三個都沒勾,那麼後面界面上的三個按鈕顯示都不可操作;

圖中下面兩個界面,前一個頁面子權限三個都勾上,那麼後面界面上的三個按鈕就變成可以操作了;

【開源架構】EFW架構中的系統權限與頁面子權限詳解

1.如何使用頁面子權限

1)在“使用者權限管理”界面維護好菜單的頁面子權限清單,并給角色配置子權限

見下圖,在紅框部分輸入權限辨別和名稱,點選儲存就可以增加一個頁面子權限,選中網格一條記錄點選删除就移除頁面子權限;一個菜單的頁面子權限的辨別不能夠重複,頁面子權限可以随便增加,但肯定要跟實際界面有關系;

維護好頁面子權限後,再選擇左邊網格中的角色,勾選頁面子權限完成權限配置;

【開源架構】EFW架構中的系統權限與頁面子權限詳解

2)界面控制器擷取頁面子權限資料,并編寫代碼控制界面展示

見下圖,bookwinController控制器可以直接得到父類BaseController中的GetPageRight屬性為頁面子權限的資料,用DataTable存儲;然後編寫代碼判斷資料中的“new”、“delete”和“export”的值是0或1,用來設定三個按鈕的狀态;

還有BaseController如何取得頁面子權限的資料,是通過架構中的ExecuteFun對象實作的,ExecuteFun是用來調用架構中所有注冊到架構中的委托代碼;

【開源架構】EFW架構中的系統權限與頁面子權限詳解

2.關于“委托代碼”的調用

上文中在擷取頁面子權限資料的時候用到了架構中的“委托代碼”,講解“委托代碼”之前先了解一下調用外部程式集代碼的三種方式:

1)引用調用,選擇項目引用可以右鍵添加外部程式集後,代碼中就可以直接使用引用程式集中定義的公共對象;

2)反射調用,項目不用引用程式集,但要知道程式集的名稱、類的名稱與方法屬性,就可以用反射方式動态調用程式集中的代碼;

3)通過架構中的委托代碼調用,程式集将代碼注冊到架構中,那麼項目中不用關心是哪個程式集,隻要使用架構中的Excutefun對象就可以調用所有注冊到架構的代碼;

第一種方式是經常用到的,用起來非常友善,但是有些情況下這種方式無法使用,比如兩個程式集互相調用的時候,就不能互相引用,因為編譯就會報錯。那麼這時候就會用到“反射”第二種方式,反射就是用起來比較麻煩,需要記住一些名詞,而且不能書寫錯誤。當程式集中的調用關系很複雜的話,“反射”這種方式用起來也麻煩,調用入口太多,容易搞錯。這時候就需要用到第三種方式“委托代碼”,這樣調用都是調用架構中的對象,但是代碼是通過委托的方式下放到不同的程式集去的;

你可能會覺得,把引用關系設計這麼複雜幹嘛,全部單向引用,都需要用到的對象就另外建立一個公共類庫不就行了。這種想法是好的,一次前期的設計得非常全面才能把公共類庫規劃得很好,還有就是把一些對象與原有程式集分離到公共類庫中,從代碼的結構上有點影響代碼的閱讀,代碼的編寫也變得複雜不連貫;是以覺得“委托代碼”是一種解決這種問題的不錯方式;

委托代碼注冊:

public class BaseLibShareFunCode : ExecuteFun
    {
        public override void LoadFun(System.Collections.Hashtable codeList)
        {
            string funName;
            FunCode code;
            //getPageRight 頁面子權限資料擷取
            //調用方法:DataTable data=(DataTable)ExecuteFun.invoke("getPageRight",1,1);
            funName = "getPageRight";
            code = delegate(object[] para)
            {
                int menuId = Convert.ToInt32(para[0]);
                int userId = Convert.ToInt32(para[1]);
                DataTable data = null;
                string strsql = @"SELECT Code,Name,
                                            (
                                            CASE WHEN 
                                            (SELECT COUNT(*) FROM BaseGroupPage a 
                                            LEFT JOIN BaseGroupUser b ON a.GroupId=b.GroupId
                                            WHERE b.UserId={1} AND a.PageId=P.Id)>0 
                                            THEN 1 ELSE 0 END
                                            ) Val
                                             FROM BasePageMenu P WHERE MenuId={0}";
                strsql = string.Format(strsql, menuId, userId);
                data = oleDb.GetDataTable(strsql);
                return data;
            };
            codeList.Add(funName, code);

            //
        }
    }      

委托代碼調用:

/// <summary>
        /// 擷取頁面子權限
        /// </summary>
        public DataTable GetPageRight
        {
            get
            {
                DataTable data = (DataTable)ExecuteFun.invoke(oleDb,"getPageRight", MenuId, GetSysLoginRight.UserId);
                return data;
            }
        }      

3.頁面子權限在不同系統Web、Winform、WCF下的差別

上文執行個體是講得Winform系統中的使用,其實三種不同系統原理都一樣,隻是系統結構的差别是以實作方式有點差別而已;

Winform系統很簡單,直接調用BaseController中的GetPageRight屬性就能擷取頁面子權限資料,界面可以直接操作GetPageRight屬性傳回的DataTable資料,編寫權限控制代碼;

public class bookwinController : BaseController
    {
        IfrmBook frmBook;
        public override void Init()
        {
            frmBook = (IfrmBook)DefaultView;
            //初始化加載書籍目錄
            GetBooks();
            GetPie();
            //擷取頁面子權限
            frmBook.SetPageRight(GetPageRight);
        }
...      

Web系統,可以從AbstractJqueryController中擷取GetPageRight屬性,但資料是DataTable結構,是以界面還需要通過Ajax向調用背景控制器将DataTable資料轉成json資料到界面JS中,再用JS代碼編寫權限控制代碼;

public class bookController : EFWCoreLib.WebFrame.Controller.AbstractJqueryController
    {
        [WebMethod]
        public void GetPageRightData()
        {
            int menuId = Convert.ToInt32(ParamsData["menuId"]);
            DataTable dt = GetPageRight(menuId);
            TxtJson = ReturnSuccess("", ToJson(dt));//前台用requestAjax請求
        }
...      
//頁面子權限控制代碼
function SetPageRight() {
    var menuId = $.query.get('MenuId');
    if (menuId) {
        requestAjax('Controller.aspx?controller=bookController&method=GetPageRightData', { menuId: menuId }, function (data) {
            PageRight = data;
            $.each(PageRight, function (i, n) {
                if (n.Code == 'new' && n.Val == 0) {
                    $('#btnNew').hide();
                }
                if (n.Code == 'delete' && n.Val == 0) {
                }
                if (n.Code == 'export' && n.Val == 0) {
                }
            });
        });
    }
}      

WCF系統,跟Web系統一樣不能從BaseWCFClientController中直接擷取,需要使用WCF服務從背景控制器中擷取GetPageRight資料,然後轉成Json資料傳遞給界面控制器,再編寫權限控制代碼;

[WCFController]
    public class bookWcfController : JsonWCFController
    {
        //根據界面傳遞的菜單ID擷取頁面子權限資料
        [WCFMethod]
        public string GetPageRightData()
        {
            int menuId = ToInt32(ParamJsonData);
            DataTable dt = GetPageRight(menuId);
            return ToJson(dt);
        }
...      
public class bookwcfclientController : BaseWCFClientController
    {
        IfrmBook frmBook;
        public override void Init()
        {
            frmBook = (IfrmBook)DefaultView;
            //初始化加載書籍目錄
            GetBooks();
            //擷取頁面子權限資料
            PageRight = ToDataTable(InvokeWCFService("bookWcfController", "GetPageRightData", ToJson(MenuId)));
            frmBook.SetPageRight(PageRight);
        }
...      

總結:EFW架構中的權限還是能滿足大部分的項目開發了,具有菜單級權限與頁面級權限,從粗到細;本文主要講解的是頁面子權限的内容,注意頁面子權限的兩部分操作是完全獨立的,定義子權限清單與編寫權限控制代碼,但是後者又依賴前者,通過辨別關聯起來;

下一章提前看:《掌握EFW架構的需要抓住以下幾個方面》

掌握和使用不同,如果你隻要求會使用EFW架構那完全沒必要深入學習架構的代碼,博文也隻學習前面幾章就行了,但如果你作為一個開發團隊的頭,講EFW架構運用在項目中的話,那你就必須深入掌握EFW架構,雖然沒必要把架構中的沒一段代碼搞清楚,但一定要做到心裡有數,能夠自主解決項目開發中遇到問題,也知道怎麼擴充架構。本章講得幾個方面是為學習架構提供一個可參考的脈絡,防止深陷在衆多功能中。

1.必備的技術知識

2.架構核心的功能點之間的關聯

3.業務比代碼更重要

4.閱讀代碼的方法,了解“代碼層次結構”優先“代碼具體細節”

5.架構開源分享的意義是一些“程式設計思路的分享”,而不是又多一個開發工具供選擇而已。是以博文更注重把架構中的核心點拿出來讨論,引導大家向更深層次的思考,找到更好的實作方法;要是寫成操作手冊一樣的文章,意義不大;

程式設計能力等級的提升是多麼的不容易,這個過程是沒有什麼具體的方法或操作步驟,而是那“一刹那”的豁然開朗;“一刹那”之後這一層的東西基本已經融會貫通、了然于胸,都能說出個之是以然來,但要達到這“一刹那”之前的積累是必不可少的,而代碼量是一個具體可參考的名額;

就跟刀客成為一流高手之前的揮刀次數;