之前netcore 2.2 的项目用到的授权方式 如以下链接的文章提到的第三种方式, Policy策略+自定义授权标签AuthorizeAttribute
ASP.Net Core下Authorization的几种方式
核心的处理方法是在AuthorizeAttribute授权标签的相应方法下将接口Controller上的自定义标签获取出来, 然后传到策略的处理接口里去做权限的判断( return HandleRequirementAsync(context, requirement, attributes); )
public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>();
var action = (context.Resource as AuthorizationFilterContext)?.ActionDescriptor as ControllerActionDescriptor;
if (action != null)
{
attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
attributes.AddRange(GetAttributes(action.MethodInfo));
}
return HandleRequirementAsync(context, requirement, attributes);
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);
private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
}
}
这个方法在升级到.net5之后, 由于AuthorizationHandlerContext类的Resource不再是AuthorizationFilterContext类型, 导致action是null拿不到自定义标签, 而且还不会报错,比较坑爹.
修正的代码如下, context.Resource已变成DefaultHttpContext, 只能从它的Endpoint的MetaData里获取到自定义的标签列表(如果确保一个接口只使用一个标签的话,使用Metadata的GetMetadata<TAttribute>()方法亦可) :
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>();
var defaultContext= context.Resource as DefaultHttpContext;
var attributes = defaultContext.GetEndpoint().Metadata.Where(p=> p is TAttribute).Select(t=>(TAttribute)t).ToList();
return HandleRequirementAsync(context, requirement, attributes);
}
最后, 发现使用这种标签授权验证的方法, 要是接口Controller上有多个相同的标签, 该标签的HandleRequirementAsync会触发多次, 再看看是否有其他更好又灵活简便的授权验证方法