asp.net core 多个授权策略选择单个策略

首先假设我们依据官方示例有这样一个自定义的授权handler

    public class FunAuthorizeAttribute : AuthorizeAttribute, IAuthorizationRequirement,IAuthorizationRequirementData
    {
        public FunAuthorizeAttribute() : this(null, true) { }
        public FunAuthorizeAttribute(string funcCodes):this(funcCodes,true){}
        public FunAuthorizeAttribute(bool isMinimumAge) : this(null, isMinimumAge){}
        public FunAuthorizeAttribute(string? funcCodes,bool isMinimumAge)
        {
            FuncCodes = funcCodes;
            IsMinimumAge = isMinimumAge;
        }
        public string? FuncCodes { get; }
        /// <summary>
        /// 是否要有18岁要求
        /// </summary>
        public bool IsMinimumAge { get; set; } = true;
        public IEnumerable<IAuthorizationRequirement> GetRequirements()
        {
            yield return this;
        }
    }
    public class FunAuthorizationHandler(ILogger<FunAuthorizationHandler> logger) : AuthorizationHandler<FunAuthorizeAttribute>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FunAuthorizeAttribute requirement)
        {
            logger.LogInformation(requirement.FuncCodes);
            var user = context.User;
            
            if (requirement.IsMinimumAge)
            {
                var age = user.Claims.FirstOrDefault(a => a.Type == "Age");
                if (age != null)
                {
                    int ageNumber = int.Parse(age.Value);
                    if (ageNumber<18)
                    {
                        context.Fail();
                        return Task.CompletedTask;
                    }
                }
            }
            if (requirement.FuncCodes == null)
            {
                context.Succeed(requirement);
                return Task.CompletedTask;
            }
            else
            {
                var funcCodes = requirement.FuncCodes.Split(',');
                var claim = user.Claims.FirstOrDefault(a => a.Type == "Funs");
                if (claim != null)
                {
                    string[] list = claim.Value.Split(',');
                    if (list != null && funcCodes.Any(a => list.Contains(a)))
                    {
                        context.Succeed(requirement);
                        return Task.CompletedTask;
                    }
                }
            }
            context.Fail();
            return Task.CompletedTask;
        }
    }
View Code

 

FunAuthorizeAttribute 可以设置功能权限和18岁成人要求,我们一般默认是所有接口通用为需要满足18岁的,所以我们可能会自定义一个contoller 父类

[FunAuthorizeAttribute]
public class ApiController : ControllerBase{}

所有Controller都继承通用这个父类;
到这一步,很多人稍微研究过授权的可能都会处理了;

但是asp.net core 的默认是需要满足所有策略的,也就是说当你在某些特定方法上加了一个[FunAuthorizeAttribute(false)],可是依旧返回是403,你的数据依旧需要满足 age>=18,因为父类有要求 IsMinimumAge=true;

此时我们更多时候想要的是我只需要验证最后一个策略,也就是[FunAuthorizeAttribute(false)],这个时候要如何处理?

    public class FunAuthorizationHandler(ILogger<FunAuthorizationHandler> logger) : IAuthorizationHandler
    {
        public async Task HandleAsync(AuthorizationHandlerContext context)
        {
            // 只处理最后一个的授权
            var list = context.Requirements.OfType<FunAuthorizeAttribute>();
            var count = list.Count();
            int i = 1;
            foreach (var req in list)
            {
                if (i == count)
                {
                    await HandleRequirementAsync(context, req).ConfigureAwait(false);
                }
                else
                {
                    context.Succeed(req);
                }
                i++;
            }
        }

        protected Task HandleRequirementAsync(AuthorizationHandlerContext context, FunAuthorizeAttribute requirement)
        {
            logger.LogInformation(requirement.FuncCodes);
            var user = context.User;

            if (requirement.IsMinimumAge)
            {
                var age = user.Claims.FirstOrDefault(a => a.Type == "Age");
                if (age != null)
                {
                    int ageNumber = int.Parse(age.Value);
                    if (ageNumber < 18)
                    {
                        context.Fail();
                        return Task.CompletedTask;
                    }
                }
            }
            if (requirement.FuncCodes == null)
            {
                context.Succeed(requirement);
                return Task.CompletedTask;
            }
            else
            {
                var funcCodes = requirement.FuncCodes.Split(',');
                var claim = user.Claims.FirstOrDefault(a => a.Type == "Funs");
                if (claim != null)
                {
                    string[] list = claim.Value.Split(',');
                    if (list != null && funcCodes.Any(a => list.Contains(a)))
                    {
                        context.Succeed(requirement);
                        return Task.CompletedTask;
                    }
                }
            }
            context.Fail();
            return Task.CompletedTask;
        }
    }
View Code

首先基础类由AuthorizationHandler<T>改为IAuthorizationHandler,在HandleAsync 方法里就可以重写自己需要的策略,我们只正常处理最后一个策略要求,其他的全部设置成功。

代码丑陋见笑了;

 

posted @ 2024-04-28 15:21  diudiu1  阅读(2)  评论(0编辑  收藏  举报