首先假设我们依据官方示例有这样一个自定义的授权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 方法里就可以重写自己需要的策略,我们只正常处理最后一个策略要求,其他的全部设置成功。
代码丑陋见笑了;