本篇目錄
介紹###
幾乎所有的企業應用都在不同程度使用了授權。授權的目的在於檢查是否允許用戶在應用程序中執行特定的操作。ABP定義了一個基於權限的基礎設施來實現授權。
關於IPermissionChecker
授權系統使用了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:系統中 唯一的名字。最好為權限的名字定義一個const字符串而不是變量字符串。我們偏向使用“.”符號用於有層次的名字,但這不是強制的。你可以設置任何你喜歡的名字,唯一的一點是保證它必須是唯一的。
- DisplayName:用於以后在UI上顯示權限的本地化字符串。
- Description:用於以后在UI上顯示權限定義的本地化字符串。
- IsGrantedByDefault:表示該權限是否授予給所有登錄的用戶,除非該權限顯式禁止未授予給用戶。該值一般默認為false。
- MultiTenancySides:對於多租戶應用,租戶或者租主可以使用同一個權限。這是一個Flags枚舉,因此一個權限可以用於租戶和租主。
- dependedFeature:可以用於聲明一個功能的依賴。因此,只有功能依賴滿足了,該權限才會被授予。
一個權限可以有父權限和子權限。雖然這不會影響權限檢查,但是在UI上組合權限有所幫助。
當創建了授權提供者之后,我們應該在模塊的PreIntialize方法中注冊它:
Configuration.Authorization.Providers.Add<MyAuthorizationProvider>();
因為授權提供者會自動地注冊到依賴注入系統中,所以,授權提供者通過一些其他資源,可以注入任何依賴(比如倉儲)來生成權限定義。
檢查權限###
使用AbpAuthorize特性
AbpAuthorize(MVC控制器是AbpMvcAuthorize,Web API控制器是AbpApiAuthorize)是最簡單也是最普通的檢查權限的方式。思考一下下面的應用服務方法:
[AbpAuthorize("Administration.UserManagement.CreateUser")]
public void CreateUser(CreateUserInput input)
{
//如果一個用戶沒有被授予 "Administration.UserManagement.CreateUser" 權限,那么ta就不能執行此方法
}
AbpAuthorize特性也會檢查當前的用戶是否已經登錄(使用IAbpSession.UserId)。因此,如果我們為一個方法聲明了AbpAuthorize,它至少會檢查登錄情況:
[AbpAuthorize]
public void SomeMethod(SomeMethodInput input)
{
//如果用戶沒有登錄,那么ta就不能執行此方法
}
AbpAuthorize特性需要注意的地方
ABP對於授權使用了強大的動態方法攔截(interception)。因此,使用AbpAuthorize特性有一些限制:
- 不能用於私有方法。
- 不能用於靜態方法。
- 不能用於非注入類的方法(我們必須要使用依賴注入)。
此外,
- 可以用於任何 public方法,如果該方法是通過接口調用的(比如應用服務通過接口使用)。
- 方法應該是virtual的,如果它是從類的引用直接調用的(比如ASP.Net MVC或者Web API的控制器)。
- 如果方法是protected的,那么它應該是 virtual的。
注意:AbpAuthorize特性有三個:
在應用服務中(應用層),我們使用Abp.Authorization.AbpAuthorize類。
在MVC控制器中(Web層),我們使用 Abp.Web.Mvc.Authorization.AbpMvcAuthorize類。
在ASP.NET Web API中,我們使用 Abp.WebApi.Authorization.AbpApiAuthorize特性。
這寫特性的差異來自繼承。在MVC端,派生自MVC自己的Authorize類。在Web API端,它派生自Web API的Authorize類。因此,它已經很好地集成到了MVC和Web API。但是在應用層,它完全是ABP自己的實現而沒有擴展任何類。
使用IPermissionChecker
雖然AbpAuthorize特性對於大多數情況相當夠用了,但是肯定存在我們會在一個方法體內檢查權限的情況。我們可以注入並使用IPermissionChecker,如下面的例子所示:
public void CreateUser(CreateOrUpdateUserInput input)
{
if (!PermissionChecker.IsGranted("Administration.UserManagement.CreateUser"))
{
throw new AbpAuthorizationException("You are not authorized to create user!");
}
//如果一個用戶沒有"Administration.UserManagement.CreateUser" 權限,那么ta不能到達該點。
}
當然,你可以編寫任何邏輯代碼,因為IsGranted僅僅返回true或者false(也有Async版本)。如果你只是檢查一個權限然后拋出一個如上所示的異常,那么你可以使用 Authorize方法:
public void CreateUser(CreateOrUpdateUserInput input)
{
PermissionChecker.Authorize("Administration.UserManagement.CreateUser");
//如果一個用戶沒有"Administration.UserManagement.CreateUser" 權限,那么ta不能到達該點。
}
因為授權一般在應用層實現,所以ApplicationService基類注入並定義了PermissionChecker屬性。這樣,權限檢查者不需要在應用服務類中注入就可以使用了。
Razor視圖
視圖基類定義了IsGranted方法來檢查當前用戶是否具有權限。因此,我們可以有條件地渲染該視圖。例子:
@if (IsGranted("Administration.UserManagement.CreateUser"))
{
<button id="CreateNewUserButton" class="btn btn-primary"><i class="fa fa-plus"></i> @L("CreateNewUser")</button>
}
客戶端(Javascript)
在客戶端,我們可以使用定義在abp.auth命名空間下的API。在大多數情況,我們需要檢查當前的用戶是否具有特定的權限(使用權限名字)。例子:
abp.auth.hasPermission('Administration.UserManagement.CreateUser');
你也可以使用abp.auth.grantedPermissions來獲得所有授權的權限或者使用 abp.auth.allPermissions來獲取所有應用中可用的權限名。
注意:自ABP 0.7.8版本開始,將javascript端的abp.auth.hasPermission更名為abp.auth.isGranted。hasPermission已經過時了。在新的項目中不要使用abp.auth.hasPermission。
權限管理者###
我們可能需要定義權限。這時可以注入並使用IPermissionManager。