【问题标题】:How to emulate the AllowAnonymousAttribute behavior?如何模拟 AllowAnonymousAttribute 行为?
【发布时间】:2015-12-09 18:09:30
【问题描述】:

我想实现一个白名单方法,默认情况下将应用 [Authorize(Roles = "Admin")] 属性。然后我想在白名单操作中指定[AllowAnonymous][AllowMember]

所以我需要创建一个类似于AllowAnonymous 的属性,但只授予“成员”角色的访问权限。 (和AllowAnonymous 一样,它应该覆盖任何可能在控制器上作为全局过滤器生效的Authorize 属性。)

我最初尝试从AllowAnonymousAttribute 继承,但我发现它是密封的。我用谷歌搜索了“继承允许匿名”,但答案让我无法理解。

我的方法是否明智?如何创建这样的属性?


更新

按照 NightOwl888 的建议和来自this page 的一些代码,我有:

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

  2. 继承了 AuthorizeAttribute 以创建一个新的,我将 应用为全局过滤器

  3. 在 AuthorizeCore() 方法中插入了几个方法来检查属性并返回 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();
        }
    }
}

【问题讨论】:

    标签: asp.net-mvc authorization custom-attributes authorize-attribute


    【解决方案1】:

    AllowAnonymous 属性的所有行为都是coded into the AuthorizeAttribute.OnAuthorize method。所以,如果你想重用这个行为,最好的方法是继承AuthorizeAttribute,然后覆盖AuthorizeCore method

    【讨论】:

    • 感谢您,感谢。我接受了您的建议,并在问题中发布了一个新的全局属性。你觉得这样合适吗?
    • 关闭。请记住,AuthorizeAttribute 中的代码可能会被多个线程同时调用。因此,使用当前上下文设置类级变量可能会导致用户之间出现问题。查看this answer(在ClaimsIdentityAuthorizationService)中的OnAuthorization 方法来解决这个问题。
    • 酷,再次感谢。我通过将filterContext.HttpContext.Items["ActionDescriptor"] = filterContext.ActionDescriptor; 添加到OnAuthorisation() 方法并从AuthorizeCore() 方法访问它来更新示例。这是一种线程安全的方法吗?抱歉所有问题,我很菜鸟,玩授权让我害怕。
    • Is that a thread safe approach? - 是的。 HttpContext.Items 集合保证始终存在于调用它的同一个请求中(这可能比同一个线程上的粒度更细)。不得不这样做似乎很奇怪。微软没有在AuthorizeCore 中使用AuthorizationContext 显然是一个设计缺陷。幸运的是,他们通过一直传递相同的上下文类型在 MVC 6 中修复了它。
    • 看来我正在尝试的事情比我最初想象的要复杂得多......非常感谢 v 提供的信息和建议,让它工作真是太好了 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-06
    • 2011-04-09
    • 2012-07-28
    • 2019-08-31
    • 2016-06-25
    • 1970-01-01
    相关资源
    最近更新 更多