如何模拟 AllowAnonymousAttribute 行为?

How to emulate the AllowAnonymousAttribute behavior?

我想实现一种默认应用 [Authorize(Roles = "Admin")] 属性的白名单方法。然后我想在白名单操作上指定 [AllowAnonymous][AllowMember]

所以我需要创建一个类似于 AllowAnonymous 的属性,但只授予 "Member" 角色的访问权限。 (与 AllowAnonymous 一样,它应该覆盖任何 Authorize 可能对控制器有效的属性作为全局过滤器。)

我最初尝试继承自AllowAnonymousAttribute,但我发现它是密封的。我用谷歌搜索 "Inherit allowanonymous" 但答案让我不知所措。

我的方法明智吗?我怎样才能创建这样的属性?


更新

根据 NightOwl888 的建议和 this page 的一些代码,我有:

  1. 创建了两个Attributes,一个允许会员,另一个public

  2. 继承了AuthorizeAttribute 新建一个我会 应用为全局过滤器

  3. 在 AuthorizeCore() 方法中插入了几个方法来检查属性和 return true

我希望我在下面的代码中没有做任何愚蠢的事情...如果它看起来不错(或不好),我会很感激。

谢谢。


namespace FP.Codebase.Attributes
{
    public class AllowPublicAccessAttribute : Attribute
    {}



    public class AllowMemberAccessAttribute : Attribute
    {}



    public class MyAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            filterContext.HttpContext.Items["ActionDescriptor"] = filterContext.ActionDescriptor;
            base.OnAuthorization(filterContext);
        }



        private bool IsAllowPublicAccessAttributeAppliedToAction(ActionDescriptor actionDescriptor)
        {
            return (actionDescriptor.IsDefined(typeof(AllowPublicAccessAttribute), inherit: true)
                || actionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowPublicAccessAttribute), inherit: true));
        }



        private bool IsAllowMemberAccessAttributeAppliedToAction(ActionDescriptor actionDescriptor)
        {
            return (actionDescriptor.IsDefined(typeof(AllowMemberAccessAttribute), inherit: true)
                || actionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowMemberAccessAttribute), inherit: true));
        }



        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var actionDescriptor = httpContext.Items["ActionDescriptor"] as ActionDescriptor;
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }

            IPrincipal user = httpContext.User;

            if (IsAllowPublicAccessAttributeAppliedToAction(actionDescriptor))
            {
                return true;
            }
            if (IsAllowMemberAccessAttributeAppliedToAction(actionDescriptor) && user.IsInRole("Member"))
            {
                return true;
            }

            if (!user.Identity.IsAuthenticated)
            {
                return false;
            }

            var _usersSplit = SplitString(Users);
            var _rolesSplit = SplitString(Roles);

            if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
            {
                return false;
            }

            if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
            {
                return false;
            }

            return true;
        }



        // copied from https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/AuthorizeAttribute.cs
        internal static string[] SplitString(string original)
        {
            if (String.IsNullOrEmpty(original))
            {
                return new string[0];
            }

            var split = from piece in original.Split(',')
                        let trimmed = piece.Trim()
                        where !String.IsNullOrEmpty(trimmed)
                        select trimmed;
            return split.ToArray();
        }
    }
}

AllowAnonymous 属性的所有行为都是 coded into the AuthorizeAttribute.OnAuthorize method. So, if you want to reuse this behavior, the best approach is to inherit AuthorizeAttribute and override the AuthorizeCore method