• 深入了解 Authorize 和 AllowAnonymous


    深入了解 Authorize 和 AllowAnonymous

    Chapter 0 - Intro

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

    Chapter 1 - 自定义 Filter V1.0

    Filter代码 V1.0

     1 /// <summary>
     2 /// 不需要登录即可访问
     3 /// </summary>
     4 public class NoPermissionRequiredAttribute : ActionFilterAttribute
     5 {
     6     public override void OnActionExecuting(ActionExecutingContext filterContext)
     7     {
     8         base.OnActionExecuting(filterContext);
     9     }
    10 }
    11 
    12 /// <summary>
    13 /// 需要登录才能进行操作
    14 /// </summary>
    15 public class PermissionRequiredAttribute : ActionFilterAttribute
    16 {
    17     public override void OnActionExecuting(ActionExecutingContext filterContext)
    18     {
    19         if (filterContext.HttpContext.Session["User"]==null)
    20         {
    21             filterContext.Result = new RedirectResult("~/Admin/Account/Login");
    22         }
    23         base.OnActionExecuting(filterContext);
    24     }
    25 }
    26 
    27 /// <summary>
    28 /// 需要有超级管理员权限
    29 /// </summary>
    30 public class AdminPermissionRequiredAttribute : ActionFilterAttribute
    31 {
    32     public override void OnActionExecuting(ActionExecutingContext filterContext)
    33     {
    34         if ((filterContext.HttpContext.Session["User"] == null) || !((filterContext.HttpContext.Session["User"] as Models.User).IsSuper))
    35         {
    36             filterContext.Result = new RedirectResult("~/Admin/Account/Login");
    37         }
    38         base.OnActionExecuting(filterContext);
    39     }
    40 }

    Chapter 2 - 控制器引用 Filter

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

     1 [Authorize]
     2 [Filters.PermissionRequired]
     3 public class AccountController : BaseAdminController
     4 {
     5     /// <summary>
     6     /// 登录页面
     7     /// </summary>
     8     /// <returns></returns>
     9     [AllowAnonymous]
    10     [Filters.NoPermissionRequired]
    11     [HttpGet]
    12     public ActionResult Login(string ReturnUrl)
    13     {
    14         if (!Url.IsLocalUrl(ReturnUrl))
    15         {
    16             ReturnUrl = "/Admin/Home/Index";
    17         }
    18         if (Helpers.AuthFormService.TryAutoLogin())
    19         {
    20             return Redirect(ReturnUrl);
    21         }
    22         return View();
    23     }
    24 
    25     /// <summary>
    26     /// 账户首页
    27     /// </summary>
    28     /// <returns></returns>
    29     public ActionResult Index()
    30     {
    31         Models.User u = Session["User"] as Models.User;
    32         return View(u);
    33     }
    34 }

    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的定义,如下图所示:

    AllowAnonymous定义:

    Authorize定义

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

    Chapter 5 - 自定义 Filter V2.0

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

     1 /// <summary>
     2 /// 需要登录才能进行操作
     3 /// </summary>
     4 public class PermissionRequiredAttribute : ActionFilterAttribute
     5 {
     6 
     7     public override void OnActionExecuting(ActionExecutingContext filterContext)
     8     {
     9         if (!filterContext.ActionDescriptor.IsDefined(typeof(NoPermissionRequiredAttribute),true))
    10         {
    11             if (filterContext.HttpContext.Session["User"] == null)
    12             {
    13                 filterContext.Result = new RedirectResult("~/Admin/Account/Login");
    14             }
    15         }            
    16         base.OnActionExecuting(filterContext);
    17     }
    18 }

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

  • 相关阅读:
    图片热点 网页划区 网页的拼接 表单
    html body的属性 格式控制标签 内容容器标签 超链接标签 图片标签 表格
    结构体
    out 传值
    c#数组,手机号随机数抽奖
    输入月份和日期,输出是今年的第多少天,利用switch和case
    c#,for穷举,百鸡百钱
    c#条件运算符的使用,判断时间是上午还是下午
    c#关于try catch finally的使用,判断日期格式是否正确
    c#数组,例题
  • 原文地址:https://www.cnblogs.com/weihanli/p/5818923.html
Copyright © 2020-2023  润新知