利用RBAC模型實現一個通用的權限管理系統

利用RBAC模型實現一個通用的權限管理系統

       本文主要描述一個通用的權限系統實現思路與過程。也是對此次製作權限管理模塊的總結。

       製作此係統的初衷是爲了讓這個權限系統得以“通用”。就是生產一個web系統通過調用這個權限系統(生成的dll文件),

就可以實現權限管理。這個權限系統會管理已生產系統的所有用戶,菜單,操作項,角色分配,權限分配,日誌等內容。

  實現此功能從正常訪問和非法訪問兩個方面入手。正常訪問即用戶登錄系統後只能看到或操作自己擁有的菜單;非法訪問即

通過拼寫url等途徑訪問系統的某個功能;所以程序除了實現用戶登錄後獲取用戶擁有的菜單權限,更要擋住用戶的非法請求。兩

者缺一不可。

一.概念

     實現這個功能主要利用RBAC權限設計模型,英文(Role-Based Access Control)譯爲基於角色的權限管理又叫基於角色的

訪問控制。

二.數據庫設計

 1.系統表:因爲要達到"通用",所以這個表會記錄各個系統。其他用戶、菜單、操作、權限表每條記錄都會對應系統代碼。

 

 字段說明:Code      —> 系統標識代碼

                  SysName  —> 系統名稱

2.菜單表:記錄菜單。每個功能當成一個菜單,菜單有url屬性,用戶通過點擊菜單來訪問對應功能;

 

 字段說明:ID                  —> 主鍵,自增標識

                  MenuName     —> 菜單名稱

        PageUrl                —> 菜單對應url

        PId                   —> 菜單父級Id

           Lv        —> 菜單等級,分一級菜單和二級菜單

                  ControllerAction  —> 菜單唯一標識,用來做權限控制

                  SystemCode    —> 系統標識代碼

3.操作表:此表主要是爲了判斷用戶是否有來操作某個具體功能,如常用的【刪除】功能等操作都放在這個表裏;

 

 字段說明:ID                —> 主鍵,自增標識

                  OprateName   —> 操作名稱

           OperateCode     —> 操作標識代碼

                  SystemCode       —> 系統標識代碼

4.用戶表:記錄所有系統的使用用戶。記錄用戶賬號、密碼等信息;

 

 字段說明:ID            —> 主鍵,自增標識

                  UserName   —> 用戶登錄名稱

        UserPwd         —> 用戶登錄密碼

                  SystemCode   —> 系統標識代碼

5.角色表:這是RBAC設計不可缺少的,記錄角色信息,不同級別的角色擁有不同的權限。給用戶分配角色也用到它;

 

 字段說明:ID             —> 主鍵,自增標識

                  RoleName    —> 角色名稱

                  SystemCode   —> 系統標識代碼

6.權限表:存放用戶的權限信息。在這個系統裏我的設計是每個菜單,每個操作都對應一個權限記錄。所以有一個字段[ActionType]

來區分是菜單還是操作;

 

 字段說明:ID             —> 主鍵,自增標識

                  PowerName —> 權限名稱

        ActionId          —> 菜單或操作ID

        ActionType      —> 區分是菜單或操作

                  SystemCode    —> 系統標識代碼

7.用戶對應角色表:這個表負責關聯用戶和角色的關係。由於初次使用RBAC模型,又爲了快速投入使用,因此在這次使用中沒有

考慮一對多的角色。所以在這個系統裏用戶和角色都是一對一的關係,每個用戶對應一個角色;

 

 字段說明:ID             —> 主鍵,自增標識

                  UserId           —> 用戶ID

        RoleId              —> 角色ID

                  SystemCode    —> 系統標識代碼

 

8.角色對應權限表:這個表負責管理角色和權限的關係。角色和權限屬於一對多的關係,每個角色對應多個權限;

 

 字段說明:ID             —> 主鍵,自增標識

                  RoleId           —> 角色ID

        PowerId           —> 權限ID

                  SystemCode    —> 系統標識代碼

9.日誌表:這個應該容易理解,日誌表記錄用戶操作系統的痕跡,像用戶信息、訪問url、時間等。

 字段說明:ID             —> 主鍵,自增標識

                  UserId           —> 操作名稱

        VisitUrl            —> 操作標識代碼

                  Remark           —> 系統標識代碼

                  CreateTime     —> 創建時間

                  SystemCode   —> 系統標識代碼

 

三.程序設計

      上面說了數據庫的構造,接下來講一下此次程序的設計方案。開篇已經提過爲了通用此項目最終生成dll文件以便其他系統調用,

當然你也可以做成webservice,還能滿足跨平臺。

       這個系統不與任何業務系統公用數據訪問層和業務邏輯層。即使兩者使用一個相同的數據庫,這個系統還是擁有獨立的數據訪

問層和業務邏輯層,這個情況只限於一個實現權限管理的“權限後臺”。

       在此我用了三層,添加了一個接口Service。其他系統只能訪問這個接口調用自己需要的方法。這樣做對於系統本身有利於避免

方法被任意調用,能實現途徑不一。對使用者也簡潔明瞭。爲了達到這個目的可以用關鍵字internal修飾數據訪問層和業務邏輯層

的類。程序結構如下圖:

 

  繼續說說這個接口提供了哪些方法和屬性吧。

1.當前登陸用戶:在系統中不少地方要用到它,比如展示登陸用戶的賬號,角色等,存放登錄用戶可以使用Session,也可使用Redis;

2.登錄/退出方法;

2.登陸用戶有權限訪問的菜單集合:提供使用用戶正常訪問的菜單,例如樹形菜單等;

3.子菜單集合:方法2也可實現,這個只不過多一個服務而已;

4.判斷操作權限的方法:數據庫中有一個操作表,通過操作代碼去權限表裏查詢。判斷登陸用戶是否擁有某一個操作的權限,例如

“刪除”功能;

5.日誌集合:滿足各個系統查看日誌的需要。

四.權限和日誌

  這裏的權限是爲了擋住非正常途徑的訪問。實現思路是通過用戶訪問的url跟用戶可以訪問的菜單屬性【ControllerAction】一一

對比。爲了便於理解,在此用開發實例說明一下

       我做業務系統時UI框架用的是MVC4.0,他很好的支持Filter。因此在權限系統三層的基礎上加了一個Filter文件夾,創建PowerAttribute

,提供驗證登錄和驗證權限兩個類。

複製代碼
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class LoginAttribute : ActionFilterAttribute
    {
        /// <summary> 登錄驗證 </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var loginUser = UserService.LoginUser;
            base.OnActionExecuting(filterContext);
            if (loginUser.ID <= 0)
            {
                filterContext.Result = new RedirectResult("/home/login");
                filterContext.Result.ExecuteResult(filterContext);
            }
        }
    }
複製代碼
複製代碼
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class PowerAttribute : LoginAttribute
    {
        /// <summary> 訪問權限驗證 </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            LoginAttribute loginAttribute = new LoginAttribute();
            loginAttribute.OnActionExecuting(filterContext);

            var routeAction = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"] + "." + 
HttpContext.Current.Request.RequestContext.RouteData.Values["Action"]; List<Menu> userOwnMenuList = MenuService.GetUserOwnMenuList().ResultModel as List<Menu> ?? new List<Menu>(); var isHavepermission = userOwnMenuList.FirstOrDefault(m => m.ControllerAction.ToLower() == routeAction.ToLower()) != null; if (!isHavepermission) { HttpContext.Current.Response.Write("您沒有權限訪問"); HttpContext.Current.Response.End(); } } }
複製代碼

  訪問【用戶列表】時,只需在對應的Action上添加特性Power即可。

    // GET: /User/List
    // 用戶列表頁
    [Power]
    [Log(Desc = "查看用戶列表")]
    public ActionResult List(string code = "", int page = 1)

  日誌實現同上,就不再敘述了。整篇文字偏多,沒有寫實現接口的代碼,是因爲這些方法實現都很基礎。不便登大雅之堂。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章