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

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

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

就能夠實現權限管理。這個權限系統會管理已生產系統的全部用戶,菜單,操做項,角色分配,權限分配,日誌等內容。數據庫

  實現此功能從正常訪問和非法訪問兩個方面入手。正常訪問即用戶登陸系統後只能看到或操做本身擁有的菜單;非法訪問即框架

經過拼寫url等途徑訪問系統的某個功能;因此程序除了實現用戶登陸後獲取用戶擁有的菜單權限,更要擋住用戶的非法請求。兩數據庫設計

者缺一不可。ide

一.概念

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

訪問控制。spa

二.數據庫設計

 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)

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

相關文章
相關標籤/搜索