文章出處

深入了解 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 了。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()