本節內容:
幾乎所有的企業應用在某引起級別上使用授權。授權用來驗證一個用戶是否允許應用里的某些指定操作。
ABP定義了一個基於許可的基礎構架來實現授權。
授權系統使用IPermissionChecker來檢查許可,雖然你用自己的方式實現它,不過在module-zero項目里已完全實現。如果沒有實現該接口,會使用NullPermissionChecker,它給每個人授予所有許可。
為每個操作定義的唯一許可必須得到授權,為使用許可要先定義一個,ABP是按模塊化設計的,所以不同的模塊可以擁有不同的許可,一個模塊為了定義它的許可,應當創建一個繼承AuthorizationProvider的類。授權供應器示例如下:
public class MyAuthorizationProvider : AuthorizationProvider { public override void SetPermissions(IPermissionDefinitionContext context) { var administration = context.CreatePermission("Administration"); var userManagement = administration.CreateChildPermission("Administration.UserManagement"); userManagement.CreateChildPermission("Administration.UserManagement.CreateUser"); var roleManagement = administration.CreateChildPermission("Administration.RoleManagement"); } }
IPermissionDefinitionContext擁有獲取和創建許可的方法。
一個許可包含一些屬性:
- Name:一個系統域內的唯一名稱,用一個字符串常量,不用可變的字符串,是一個好的做法。在分級里我們更喜歡用.(點)號來命名,但它不是必須的,你設置為你喜歡的名稱,唯一的規則是一定要唯一。
- DisplayName:一個本地化的用來之后在UI上顯示許可的文本。
- Description:一個本地化的用來之后在UI上顯示許可描述的文本。
- MultiTenancySides:在多租戶應用里,許可可被租戶或宿主使用,這是一個標記性的枚舉,所以一個許可可同時被租戶和宿主使用。
- DependedFeature:用來表明一個對Feature(特色)的依賴,所以這個許可只有在滿足Feature(特色)依賴時才會被允許。
一個許可可以有一個父許可和多個子許可,雖然這對於許可檢查沒有什么作用,但可能有助於在UI上組織許可。
創建一個授權供應器之后,我們應當在我們模塊的預初始化方法里注冊它:
Configuration.Authorization.Providers.Add<MyAuthorizationProvider>();
授權供應器被自動注冊到依賴注入里,所以一個授權供應器可以注入任何的依賴(如一個倉儲),從而可以使用其它的源來定義許可。
檢查許可
AbpAuthorize(AbpMvcAuthorize用於Mvc控制器,AbpApiAuthorize用於Web Api控制器)特性,是使用許可最簡單也是最常用的方式。假設有一個應用服務方法如下所示:
[AbpAuthorize("Administration.UserManagement.CreateUser")] public void CreateUser(CreateUserInput input) { //A user can not execute this method if he is not granted for "Administration.UserManagement.CreateUser" permission. }
CreateUser方法不能被沒有“Administration.UserManagement.CreateUser”許可的用戶調用。
AbpAuthorize特性也檢查當前用戶是否已登錄(使用IAbp.Session.UsrId),所以,如果我們為一個方法聲明一個AbpAuthorize,它只用來檢查用戶是否已登錄:
[AbpAuthorize] public void SomeMethod(SomeMethodInput input) {
//用戶如果未登錄,不能執行這個方法 }
ABP為授權使用強大的動態方法攔截,所以對於使用AbpAuthorize特性的方法有些限制:
- 不能用於私有方法。
- 不能用於靜態方法。
- 不能用於無注入的類里的方法(我們必須使用依賴注入)。
同時,可用於:
- 任何通過接口調用的public方法(如通過接口使用應用服務)。
- 一個直接通過類引用(如Asp.Net Mvc或Web Api控制器)調用的virtual方法。
- 一個protected virtual方法。
注意:有4類授權特性:
- 在一個應用服務里(應用層)里,我們使用Abp.Authorization.AbpAuthorize特性。
- 在一個Mvc控制器(web層)里,我們使用Abp.Web.Mvc.Authorization.AbpMvcAuthorize特性。
- 在一個Asp.net Web Api里,我們使用Abp.WebApi.Authorization.AbpApiAuthorization特性。
- 在一個Asp.net Core里,我們使用Abp.AspNetCore.Mvc.Authorization.AbpMvcAuthorize特性。
這些不同來自於繼承,在應用層里,ABP完整地實現了,也沒有擴展任何類,但是在Mvc和Web Api里,它從自身框架的Authorize特性繼承。
我們可以為應用服務添加AbpAllowAnonymous特性來禁用一個方法/類的授權,使用框架自身的AllowAnonymous特性來禁用Mvc、Web Api、Asp.net Core控制器的授權。
盡管AbpAuthorize特性能完美應對大部分情況,但有些情況我們必須要在方法內檢查一個許可,這時我們可以注入並使用IPermissionChecker,如下所示:
public void CreateUser(CreateOrUpdateUserInput input) { if (!PermissionChecker.IsGranted("Administration.UserManagement.CreateUser")) { throw new AbpAuthorizationException("You are not authorized to create user!"); }
//一個用戶如果沒有經過“Administration.usermanagerment.CreateUser”許可的允許,是不可以到達這里的。 }
盡管IsGranted只是簡單的返回true或false,但你也可以編寫任何邏輯(IsGranted也有異步版本)。如果你像上面那樣,只是簡單的檢查一個許可並拋出一個異常,你可以使用Authorize方法:
public void CreateUser(CreateOrUpdateUserInput input) { PermissionChecker.Authorize("Administration.UserManagement.CreateUser");
//一個用戶如果沒有經過“Administration.usermanagerment.CreateUser”許可的允許,是不可以到達這里的。
}
由於授權的廣泛使用,ApplicationService和一些通用的基類注入並定義了PermissionChecker屬性,因此,在應用服務類里,不需要注入就可以使用許可檢查器。
基視圖類已經定義了IsGranted方法來檢查當前用戶是否有許可證,因此,我們可以有條件的渲染視圖,例如:
@if (IsGranted("Administration.UserManagement.CreateUser")) { <button id="CreateNewUserButton" class="btn btn-primary"><i class="fa fa-plus"></i> @L("CreateNewUser")</button> }
在客戶端里,我們可以使用定義在abp.auth命名空間里的API,大部分情況下,我們需要檢查當前用戶是否有一個指定的許可(使用許可名稱),例如:
abp.auth.isGranted('Administration.UserManagement.CreateUser');
你也可以使用abp.auth.grantedPermissions獲取所有授予權限或abp.auth.allPerssions獲取所有可用的許可名稱。在運行時里查看abp.auth命名空間的其它API。
我們可能會用到許可的定義,這里可以注入並使用IPermissionManager。