ABP module-zero +AdminLTE+Bootstrap Table+jQuery權限管理系統第十三節--RBAC模式及ABP權限管理(附贈福利)

ABP+AdminLTE+Bootstrap Table權限管理系統一期
Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMSjavascript

角色訪問控制(RBAC)

角色訪問控制(RBAC)應該是目前用得最多也是關注最多的權限管理模型了。
權限(Permission)與角色(Role)相關聯,用戶(User)經過成爲適當角色的成員而獲得這些角色的權限。這就極大地簡化了權限的管理。
RBAC引入了角色(Role)概念,目的應該是解耦了PermissionUser之間的關係,直接受權給Role,而不是直接受權給用戶,或者用戶組。
基於角色的訪問控制方法(RBAC)的顯著的兩大特徵是:html

  1. 因爲角色/權限之間的變化比角色/用戶關係之間的變化相對要慢得多,減少了受權管理的複雜性,下降管理開銷。
  2. 靈活地支持企業的安全策略,並對企業的變化有很大的伸縮性。
    RBAC支持三個著名的安全原則:最小權限原則,責任分離原則和數據抽象原則。
    (1)最小權限原則之因此被RBAC所支持,是由於RBAC能夠將其角色配置成其完成任務所須要的最小的權限集。
    (2)責任分離原則能夠經過調用相互獨立互斥的角色來共同完成敏感的任務而體現,好比要求一個計賬員和財務管理員共參與同一過賬
    (3)數據抽象能夠經過權限的抽象來體現,如財務操做用借款、存款等抽象權限,而不用操做系統提供的典型的讀、寫、執行權限。然而這些原則必須經過RBAC各部件的詳細配置才能得以體現。

RBAC結構

1.png

RBAC認爲權限受權其實是Who、What、How的問題。在RBAC模型中,who、what、how構成了訪問權限三元組,也就是「Who對What(Which)進行How的操做」。前端

  • Who:權限的擁用者或主體(如Principal、User、Group、Role、Actor等等)
  • What:權限針對的對象或資源(Resource、Class)。
  • How:具體的權限(Privilege,正向受權與負向受權)。
  • Operator:操做。代表對What的How操做。也就是Privilege+Resource
  • Role:角色,必定數量的權限的集合。權限分配的單位與載體,目的是隔離User與Privilege的邏輯關係.
  • Group:用戶組,權限分配的單位與載體。權限不考慮分配給特定的用戶而給組。組能夠包括組(以實現權限的繼承),也能夠包含用戶,組內用戶繼承組的權限。User與Group是多對多的關係。Group能夠層次化,以知足不一樣層級權限控制的要求。
  1. RBAC的關注點在於Role和User, Permission的關係。稱爲User assignment(UA)Permission assignment(PA).關係的左右兩邊都是Many-to-Many關係。就是user能夠有多個role,role能夠包括多個user。
  2. 凡是用過RDBMS都知道,n:m 的關係須要一箇中間表來保存兩個表的關係。這UA和PA就至關於中間表。事實上,整個RBAC都是基於關係模型。
  3. Session在RBAC中是比較隱晦的一個元素。標準上說:每一個Session是一個映射,一個用戶到多個role的映射。當一個用戶激活他全部角色的一個子集的時候,創建一個session。每一個Session和單個的user關聯,而且每一個User能夠關聯到一或多個Session.
  4. 在RBAC系統中,User其實是在扮演角色(Role),能夠用Actor來取代User,這個想法來自於Business Modeling With UML一書Actor-Role模式。考慮到多人能夠有相同權限,RBAC引入了Group的概念。Group一樣也看做是Actor。而User的概念就具象到一我的。
    這裏的Group和GBAC(Group-Based Access Control)中的
  5. Group(組)不一樣。GBAC多用於操做系統中。其中的Group直接和權限相關聯,實際上RBAC也借鑑了一些GBAC的概念。
  6. Group和User都和組織機構有關,但不是組織機構。兩者在概念上是不一樣的。組織機構是物理存在的公司結構的抽象模型,包括部門,人,職位等等,而權限模型是對抽象概念描述。組織結構通常用Martin fowler的Party或責任模式來建模。
  7. Party模式中的Person和User的關係,是每一個Person能夠對應到一個User,但可能不是全部的User都有對應的Person。Party中的部門Department或組織Organization,均可以對應到Group。反之Group未必對應一個實際的機構。例如,能夠有副經理這個Group,這是多人有相同職責。
  8. 引入Group這個概念,除了用來解決多人相同角色問題外,還用以解決組織機構的另外一種受權問題:例如,A部門的新聞我但願全部的A部門的人都能看。有了這樣一個A部門對應的Group,就可直接受權給這個Group。

ABP權限管理

首先ABP權限管理也是基於RBAC的。
在 RBAC之中,包含用戶users(USERS)、角色roles(ROLES)、目標objects(OBS)、操做operations(OPS)、許可權permissions(PRMS)五個基本數據元素,權限被賦予角色,而不是用戶,當一個角色被指定給一個用戶時,此用戶就擁有了該角色所包含的權限。會話sessions是用戶與激活的角色集合之間的映射。
而後咱們來看一下一開始就生成的AbpPermissions表。
2.pngjava

咱們能夠看到一個權限(AbpPermissions)有如下屬性:
Name:系統範圍內的惟一名字。把它定義爲一個字符串常量是個不錯的注意。咱們傾向於將「.」分割不一樣的層級,但並不要求這麼作。你能夠設置你任何喜歡的名字。惟一的規則就是這個名字必須是惟一的。git

  • Display Name:使用一個本地化的字符串去顯示權限到UI。
  • Description:和Display Name相似。
  • IsGrantedByDefault:此權限是否受權給(已登錄)全部用戶,除非顯示指定。一般設置爲False(默認值)。
  • MultiTenancySides:對租戶應用程序,一個權限能夠基於租戶或者主機(原文:host)。這是個枚舉標識,所以權限能夠應用於不一樣方面。一個權限能夠有父權限和子權限。

定義權限

前面幾篇文章,咱們已經完成了用戶詳情列表的增刪改查。
這裏咱們來給他們加上權限,首先,在module-zero項目中已經完整實現了。咱們先看下默認已經存在的代碼。github

public class ABPCMSAuthorizationProvider : AuthorizationProvider
    {
        public override void SetPermissions(IPermissionDefinitionContext context)
        {
            context.CreatePermission(PermissionNames.Pages_Users, L("Users"));
            context.CreatePermission(PermissionNames.Pages_Roles, L("Roles"));
            context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host);
        }
        private static ILocalizableString L(string name)
        {
            return new LocalizableString(name, ABPCMSConsts.LocalizationSourceName);
        }
    }

咱們仿照這段代碼,新建一個類UserInfoAuthorizationProvider,繼承自AuthorizationProvider,看下代碼:web

public class UserInfoAuthorizationProvider: AuthorizationProvider
    {
        public override void SetPermissions(IPermissionDefinitionContext context)
        {

            var pages = context.GetPermissionOrNull(PermissionNames.Pages);
            if (pages == null)
                pages = context.CreatePermission(PermissionNames.Pages, L("Pages"));


            var UserInfos= pages.CreateChildPermission(PermissionNames.Pages_UserInfos, L("UserInfos"));
            UserInfos.CreateChildPermission(PermissionNames.Pages_UserInfos_Create, L("UserInfosCreate"));
            UserInfos.CreateChildPermission(PermissionNames.Pages_UserInfos_Delete, L("UserInfosDelete"));
            UserInfos.CreateChildPermission(PermissionNames.Pages_UserInfos_Update, L("UserInfosUpdate"));
        }

        private static ILocalizableString L(string name)
        {
            return new LocalizableString(name, ABPCMSConsts.LocalizationSourceName);
        }
    }

而後再PermissionNames中依樣添加以下常量。數據庫

public static class PermissionNames
    {
        public const string Pages_Tenants = "Pages.Tenants";

        public const string Pages_Users = "Pages.Users";

        public const string Pages_Roles = "Pages.Roles";


        public const string Pages = "Pages";

        public const string Pages_UserInfos = "Pages.UserInfos";

        public const string Pages_UserInfos_Create = "Pages.UserInfo.Create";

        public const string Pages_UserInfos_Delete = "Pages.UserInfo.Delete";

        public const string Pages_UserInfos_Update = "Pages.UserInfo.Update";
    }

註冊TaskAuthorizationProvider

定位到ABPCMSCoreModule.cs,這裏已經有關於 Configuration.Authorization.Providers.Add<ABPCMSAuthorizationProvider>();
咱們在他的下面補上咱們本身的類。
Configuration.Authorization.Providers.Add<UserInfoAuthorizationProvider>();安全

給admin賦值

定位到HostRoleAndUserCreatorTenantRoleAndUserBuilder
而後手動在下面添加上以下代碼。session

//Grant all tenant permissions
                var permissions = PermissionFinder
                    .GetAllPermissions(new ABPCMSAuthorizationProvider())
                    .Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Host))
                    .ToList();

在這段代碼之下,添加以下代碼。

//將UserInfoAuthorizationProvider相關Permission賦予給Admin
                var UserInfoAuthorization =
                    PermissionFinder.GetAllPermissions(new UserInfoAuthorizationProvider()).ToList();
                permissions.AddRange(UserInfoAuthorization);

刪除數據庫執行命令並生成數據庫

有了上面的基礎,咱們先刪除數據庫,在生成數據庫,有人說這裏爲何要刪除數據庫,由於在在ABP模板項目中暫未提供用戶角色權限管理功能,但在AbpZero中提供了該功能,支持按用戶或角色賦予權限,在數據庫初始化的時候,將權限賦給Admin。咱們已經建立了數據庫,因此要刪除數據庫從新初始化。
5.png
執行update-database -Verbose命令,因而生成數據庫以下。

6.png

有了數據,admin用戶已經賦予了權限,天然不須要咱們去管,可是若是咱們切換用戶進來,就沒有權限,咱們怎麼出給他加上權限呢。
咱們直接在控制方法上添加上標籤[AbpAuthorize(PermissionNames.Pages_UserInfos)]就能夠了

[AbpAuthorize(PermissionNames.Pages_UserInfos)]
        [HttpGet]
        [DontWrapResult]

        public async Task<ActionResult> GetUserInfo()
        {
            string pageNumber = string.IsNullOrWhiteSpace(Request["pageNumber"]) ? "0" : Request["pageNumber"];
            string pageSize = string.IsNullOrWhiteSpace(Request["pageSize"]) ? "20" : Request["pageSize"];
            var users = (await _userAppService.GetAll(new PagedResultRequestDto { MaxResultCount = int.MaxValue })).Items;
            var  Userlist = users.Skip(int.Parse(pageNumber) * int.Parse(pageSize)).Take(int.Parse(pageSize)).ToList();
            int totaldata = Userlist.Count();
            var result = new { total = 10, rows = Userlist };
            return Json(result, JsonRequestBehavior.AllowGet);
        }

同時這裏是用區別的。

  1. 在應用服務層中咱們直接直接使用[AbpAuthorize]特性,
  2. 但在MVC控制器中使用[AbpMvcAuthorize]特性,
  3. Web API控制器中使用[AbpApiAuthorize]
    AbpAuthorize屬性說明(AbpAuthorize attribute notes)
    Abp使用動態方法攔截進行權限驗證。所以,使用AbpAuthorize特性的方法會有些限制。以下:
  • 不能應用於私有(private)方法
  • 不能應用於靜態(static)方法
  • 不能應用於非注入(non-injected)類(咱們必須用依賴注入)。
    此外,
  • AbpAuthorize特性能夠應用於任何的Public方法,若是此方法被接口調用(好比在Application Services中經過接口調用)
  • 方法是虛(virtual)方法,若是此方法直接被類引用進行調用(像是ASP.NET MVC 或 Web API 的控制器)。
  • 方式是虛(virtual)方法,若是此方法是protected
    注意:有三種AbpAuthorize 特性:
    在應用程序服務中(application layer),咱們使用Abp.Authorization.AbpAuthorize
  • 在MVC控制器(web layer)中,咱們使用Abp.Web.Mvc.Authorization.AbpMvcAuthorize
  • 在ASP.NET Web API,咱們使用 Abp.WebApi.Authorization.AbpApiAuthorize
    這三個類繼承自不一樣的地方。
  • 在MVC中,它繼承自MVC本身的Abp.Web.Mvc.Authorization.AbpMvcAuthorize類。
  • 在Web API,它繼承自Web API 的Abp.WebApi.Authorization.AbpApiAuthorize類。所以,它最好是繼承到MVC和Web API中。
  • 可是,在Application 層,它徹底是由Abp本身實現沒有擴展子任何類。

IPermissionChecker及前端受權

  1. AbpAuthorize適用於大部分的狀況,可是某些狀況下,咱們仍是須要本身在方法體裏進行權限驗證。咱們能夠注入和使用IPermissionChecker對象。以下邊的代碼所示:
public void CreateUser(CreateOrUpdateUserInput input)
{
    if (!PermissionChecker.IsGranted("Administration.UserManagement.CreateUser"))
    {
        throw new AbpAuthorizationException("You are not authorized to create user!");
    }

    //A user can not reach this point if he is not granted for "Administration.UserManagement.CreateUser" permission.
}

由於受權通常在應用服務層中進行,因此ABP默認在ApplicationService基類注入並定義了PermissionChecker屬性。這樣,在應用服務層就能夠直接使用PermissionChecker屬性進行權限檢查。以下面的代碼:

protected override async Task<User> GetEntityByIdAsync(long id)
        {
            bool UserInfos = PermissionChecker.IsGranted(PermissionNames.Pages_UserInfos);
            //若是當前人員沒有權限,則拋出異常
            if (!UserInfos)
            {
                throw new AbpAuthorizationException("沒有權限!");
            }
            var user = Repository.GetAllIncluding(x => x.Roles).FirstOrDefault(x => x.Id == id);
            return await Task.FromResult(user);
        }
  1. 前臺html ,javascript頁面中加入之前代碼便可過濾權限:
@if (IsGranted(PermissionNames.Pages_UserInfos))
{
 //業務代碼
}
  1. 咱們可使用定義在abp.auth命名空間下的API.
    abp.auth.hasPermission('PermissionNames.Pages_UserInfos);
    你也可使用abp.auth.grantedPermissions來得到全部受權的權限或者使用 abp.auth.allPermissions來獲取全部應用中可用的權限名。

注意:自ABP 0.7.8版本開始,將javascript端的abp.auth.hasPermission改名爲abp.auth.isGranted。hasPermission已通過時了。在新的項目中不要使用abp.auth.hasPermission。

總結

其實ABP module-zero中的權限管理讓人痛苦,若是我要去對AbpPermissions表等其餘表進行增刪查改的時候,很痛苦,或者給要admin賦值的時候不可能每次都刪數據庫去實現,雖然在abp zero已經實現。我以爲最好的方式是不要module-zero那套東西,一切都本身去建立一套RBAC。
送上本文源碼:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS。

最後送上福利。

github地址: https://github.com/Jimmey-Jiang/WY.MVC.RMS
一套完整權限管理系統,codefirst,直接生成數據庫可用。
12.png

本章項目圖

 1.png

2.png

3.png

相關文章
相關標籤/搜索