前言

在使用 abp 開發業務功能時,會遇到公用同一個類的情況,在給這個類配置許可權時,就要新增多個 AuthorizeAttribute,類似下面這樣:

    [Authorize(DcsPermissions.DocCenter.Doc.Default)]
[Authorize(DcsPermissions.WorkingPlatform.MyDraft.Default)]
public class DocAppService : DcsAppServiceBase, IDocAppService
{
// ......
}

但是 abp 在驗證時,會以且的方式驗證這兩個 Policy,只要一個沒有許可權,則返回 403 狀態碼。如果想以或的方式(只要有一個有許可權,那麼就返回有許可權)驗證如何做呢?通過檢視 abp 原始碼,我們可以新增一個 IMethodInvocationAuthorizationService 介面的實現替換掉 abp 預設的實現 MethodInvocationAuthorizationService 。這個類實現的唯一目的就是通過 AuthorizeAttribute 構造出 AuthorizationPolicy 然後使用 IAbpAuthorizationService 驗證許可權。下面看看我如何實現或的方式進行驗證許可權吧。

實現

程式碼不多,就直接看下面的程式碼吧

    [Dependency(ReplaceServices = true)]
public class MyMethodInvocationAuthorizationService : IMethodInvocationAuthorizationService, ITransientDependency
{
private readonly IAbpAuthorizationService _abpAuthorizationService; public AutobioMethodInvocationAuthorizationService(IAbpAuthorizationService abpAuthorizationService)
{
this._abpAuthorizationService = abpAuthorizationService;
} public async Task CheckAsync(MethodInvocationAuthorizationContext context)
{
if ( this.AllowAnonymous(context))
{
return;
} var policyNames = this.GetAuthorizationDataPolicyNames(context.Method);
if ( policyNames.Any() )
{
var isGranted = await this._abpAuthorizationService.IsGrantedAnyAsync(policyNames);
if ( !isGranted )
{
throw new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGranted);
}
}
} protected virtual bool AllowAnonymous(MethodInvocationAuthorizationContext context)
=> context.Method.GetCustomAttributes(true).OfType<IAllowAnonymous>().Any(); protected virtual string[] GetAuthorizationDataPolicyNames(MethodInfo methodInfo)
{
var attributes = methodInfo
.GetCustomAttributes(true)
.OfType<IAuthorizeData>(); if (methodInfo.IsPublic && methodInfo.DeclaringType != null)
{
attributes = attributes
.Union(
methodInfo.DeclaringType
.GetCustomAttributes(true)
.OfType<IAuthorizeData>()
);
} return attributes.Where(_ => !string.IsNullOrWhiteSpace(_.Policy)).Select(_ => _.Policy).ToArray();
}
}

這裡面主要利益於 abp 提供了 IsGrantedAnyAsync 擴充套件方法。

總結

打算把這個想法提個 PR 給 abp 專案。整個擴充套件過程下來的感覺 abp 挺靈活的。abp 預設達不到的要求,幾乎都可以通過擴充套件它來解決掉。