美文网首页Amazing .NETdotNET.NET
深入了解 Authorize 和 AllowAnonymous

深入了解 Authorize 和 AllowAnonymous

作者: 天天向上卡索 | 来源:发表于2016-08-29 17:35 被阅读2021次

    深入了解 Authorize 和 AllowAnonymous

    Chapter 0 - Intro

    最近做的一个项目的时候,自定义授权 Attribute 来区分用户权限,我的项目不太大,权限控制也不是很复杂,只涉及到匿名、普通用户、超级管理员。
    权限验证方式使用的是默认的 MemberShip 认证结合自己自定义的 权限验证 Filter。

    Chapter 1 - 自定义 Filter V1.0

    Filter代码 V1.0

    
        /// <summary>
        /// 不需要登录即可访问
        /// </summary>
        public class NoPermissionRequiredAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                base.OnActionExecuting(filterContext);
            }
        }
    
        /// <summary>
        /// 需要登录才能进行操作
        /// </summary>
        public class PermissionRequiredAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                if (filterContext.HttpContext.Session["User"]==null)
                {
                    filterContext.Result = new RedirectResult("~/Admin/Account/Login");
                }
                base.OnActionExecuting(filterContext);
            }
        }
    
        /// <summary>
        /// 需要有超级管理员权限
        /// </summary>
        public class AdminPermissionRequiredAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                if ((filterContext.HttpContext.Session["User"] == null) || !((filterContext.HttpContext.Session["User"] as Models.User).IsSuper))
                {
                    filterContext.Result = new RedirectResult("~/Admin/Account/Login");
                }
                base.OnActionExecuting(filterContext);
            }
        }
    
    

    Chapter 2 - 控制器引用 Filter

    控制器代码中引用Filter 代码:

    
        [Authorize]
        [Filters.PermissionRequired]
        public class AccountController : BaseAdminController
        {
            /// <summary>
            /// 登录页面
            /// </summary>
            /// <returns></returns>
            [AllowAnonymous]
            [Filters.NoPermissionRequired]
            [HttpGet]
            public ActionResult Login(string ReturnUrl)
            {
                if (!Url.IsLocalUrl(ReturnUrl))
                {
                    ReturnUrl = "/Admin/Home/Index";
                }
                if (Helpers.AuthFormService.TryAutoLogin())
                {
                    return Redirect(ReturnUrl);
                }
                return View();
            }
    
            /// <summary>
            /// 账户首页
            /// </summary>
            /// <returns></returns>
            public ActionResult Index()
            {
                Models.User u = Session["User"] as Models.User;
                return View(u);
            }
        }
    
    

    Chapter 3 - 运行代码

    开始调试代码,访问这个 Login Action 时就直接崩了,一直在重定向到登录页面。
    于是就想为什么会出现这样的情况呢,只使用 [Authorize][AllowAnonymous] 的时候是不会出现这种问题的,
    但是为什么自定义 Filter 的时候会出现这样的问题呢,是哪里出现的问题呢。
    首先自带的[Authorize][AllowAnonymous] 是基于 就近原则 的,离的越近的 Filter 的权限越高会覆盖掉父级定义的 Filter。
    但是自定义的 Filter 却并没有依照 就近原则 这一原则来控制权限,所以可能内部并不是靠判断哪个 Filter 离得近就用哪个 Filter的,下一步反编译 MVC 代码,看 MVC 是怎么样处理 [Authorize][AllowAnonymous]

    Chapter 4 - 反编译分析出现问题的原因

    利用 .Net 反编译工具 Reflector 或 JustDecompile反编译 System.Web.Mvc.dll ,在命名空间 System.Web.Mvc 下可以找到 AuthorizeAllowAnonymous的定义,如下图所示:

    system.web.mvc.png

    AllowAnonymous定义:

    AllowAnonymous.png

    Authorize定义

    Authorize.png Authorize.OnAuthorization.png

    通过上面的 Authorize.OnAuthorization 方法的定义基本可以知道问题出现在哪里了,Authorize 在进行权限验证的时候会判断当前请求的 Controller 和 Action 上是否有 AllowAnonymous 定义,如果有定义则不进行验证,跳过验证,只有在 当前请求的 Controller 和 Action 上都没有 AllowAnonymous 时才会进行权限验证。

    Chapter 5 - 自定义 Filter V2.0

    知道问题出现在哪里了,就开始修改自定义的 Filter 代码吧,修改之后的代码如下所示:

    
        /// <summary>
        /// 需要登录才能进行操作
        /// </summary>
        public class PermissionRequiredAttribute : ActionFilterAttribute
        {
    
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                if (!filterContext.ActionDescriptor.IsDefined(typeof(NoPermissionRequiredAttribute),true))
                {
                    if (filterContext.HttpContext.Session["User"] == null)
                    {
                        filterContext.Result = new RedirectResult("~/Admin/Account/Login");
                    }
                }            
                base.OnActionExecuting(filterContext);
            }
        }
    
    

    修改之后再次进行调试,导航到登录页面就不会再出现重定向的问题,就实现了按 就近原则 来决定 Filter 的优先级的自定义的 Filter 了。

    相关文章

      网友评论

        本文标题:深入了解 Authorize 和 AllowAnonymous

        本文链接:https://www.haomeiwen.com/subject/wizxettx.html