常見的Controller定義方式:
public class HomeController : Controller { public ActionResult Index() { return View(); } }
如果對Action的操作需要權限管理的話,需要在Controller或者Action上面添加AuthorizeAttribute屬性或者AllowAnonymousAttribute屬性。
AllowAnonymousAttribute的意思很明確,允許匿名訪問。
AuthorizeAttribute類型有幾個屬性:Roles,Users,TypeId。
當用戶請求一個Action時,會調用OnAuthorization方法。那么,我們來看看這個方法里面的代碼是什么:
public virtual void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } if (OutputCacheAttribute.IsChildActionCacheActive(filterContext)) { throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache); } bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true); if (skipAuthorization) { return; } if (AuthorizeCore(filterContext.HttpContext)) { HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; cachePolicy.SetProxyMaxAge(new TimeSpan(0)); cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); } else { HandleUnauthorizedRequest(filterContext); } }
中間有一段是判斷Action或者Controller是否被屬性AllowAnonymousAttribute描述,如果有,則返回。也就是說,無論Action或者是Controller哪一個上面被定義了[AllowAnonymous]屬性,那么,這個Action就會跳過驗證。
如果沒有的話,會判斷函數AuthorizeCore(filterContext.HttpContext)執行的結果是否為true,這樣,我們進一步看函數AuthorizeCore里面的代碼:
protected virtual bool AuthorizeCore(HttpContextBase httpContext) { if (httpContext == null) { throw new ArgumentNullException("httpContext"); } IPrincipal user = httpContext.User; if (!user.Identity.IsAuthenticated) { return false; } 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; }
邏輯比較清晰,如果用戶沒有登錄,返回false;如果授權用戶組長度大於0,但同時不包含當前用戶,返回false;如果授權角色組長度大於0,但同時不包含當前用戶所在的任何角色,返回false;符合前面所有的條件,則返回true。
到此,授權驗證的上下邏輯算是比較明了。
問題
實際操作中出現了疑惑:
如果在Controller那里定義了角色為"Users,Admin"的授權,而在Action處定義其他角色的Authorize,會怎么樣呢?
測試思路,自定義一個CustomAuthorize,override上述兩個函數(這兩個函數都是virtual的),代碼復制微軟的源碼,加斷點調試。(重寫的代碼就不展示了。大部分復制,小部分微調下。),控制器代碼如下:
[CustomAuthorize(Roles="Users,Admin")] public class HomeController : Controller { public ActionResult Index() { return View(); } [CustomAuthorize(Roles = "AAAAA")] public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } }
調試模式啟動Home下面的About頁面,在OnAuthorization里面加斷點,可以看到如下數據:
1. 在filterContext.ActionDescriptor和filterContext.ActionDescriptor.ControllerDescriptor里面可以看到各自的Roles內容
2. base.Roles的值為"Users,Admin"。
由此,我們可以得出:
當Controller和Action都出現了角色授權時,多個授權不是合並,也不是取Action上面的,而是直接取Controller上面定義的角色,繼而判斷當前用戶是否有授權。
Users是不是也是這樣的,有興趣的童鞋可以自己調試看看o(∩_∩)o ~