abp 以或的方式驗證多個 AuthorizeAttribute


前言

在使用 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 默認達不到的要求,幾乎都可以通過擴展它來解決掉。

這個方式目前測試下來有個問題,如果無權限,則返回的狀態碼是500,而非 403.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM