MVC源碼學習之AuthorizeAttribute


常見的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 ~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM