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; } }
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; } }
首先基础类由AuthorizationHandler<T>改为IAuthorizationHandler,在HandleAsync 方法里就可以重写自己需要的策略,我们只正常处理最后一个策略要求,其他的全部设置成功。
代码丑陋见笑了;