【ASP.NET MVC系列】淺談ASP.NET MVC資源過濾和受權

最近比較忙,博客好久沒更新了,不少博友問什麼時候更新博文,所以,今天就花了點時間,寫了本篇文章,希望你們喜歡。html

本篇文章不適合初學者,須要對ASP.NET MVC具備必定基礎。程序員

本篇文章主要從ASP.NET MVC 基架角度去分析MVC框架是如何實現資源過濾,資源受權,感興趣的,歡迎閱讀。瀏覽器

相關文章,請參與ASP.NET MVC系列緩存

一 ASP.NET MVC框架驗證機制app

爲了更加透徹地瞭解MVC的過濾機制,我簡要地畫了以下UML圖。框架

 下面,咱們根據如上的UML圖來簡要分析一下。ide

(一)MVC基架過濾機制根接口函數

根接口:本文指在繼承關係中的根節點,至關於類的祖宗對象Object。工具

從上圖中,很容易看出MVC過濾機制的根接口主要有六大類型接口:_Attribute,IMvcFilter,IActionFilter,IResultFilter,IExceptionFilter和IAuthorizationFilter。this

1._Attribute

_Attribute接口主要提供一些非託管服務。

2.IMvcFilter

該接口主要用於定義篩選器順序和是否容許多個篩選器,如當咱們給某個action限定多個特性時的執行順序問題。

[Filter1(Order = 3)]
[Filter2(Order = 2)]
[Filter3(Order = 1)]
public ActionResult Index()
{
    return View(); ;
}

 

 

3.IActionFilter

該接口主要定義操做的篩選,在執行操做方法先後,分別調用方法OnActionExecuting(ActionExecutingContext filterContext)和方法OnActionExecuted(ActionExecutedContext filterContext)。IResult也有相似兩個方法。

 

4.IResultFilter

該接口主要用做操做結果的篩選。對於MVC模式開發的程序員來講,ActionResult再熟悉不過了,然而,MVC機制會在操做結果執行先後,分別執行OnResultExecuting(ResultExecutingContext filterContext)方法和OnResultExecuted(ResultExecutedContext filterContext)方法,而後再將最終結果Responce給用戶,

5.IExceptionFilter

該接口主要是用來處理系統異常問題,如在項目中常常用到的throw new Exception();

6.IAuthorizationFilter

該接口用來定義資源的篩選和受權,在項目中,主要用作權限管理。

 

 (二) 三個抽象接口

從上圖繼承圖中,不難看出,MVC過濾機制,提供了三個重要的抽象類,分別爲:_Attribute,FilterAttribute和ActionFilterAttribute

 1.ActionFilterAttribute

從繼承圖中知道,ActionFilterAttribute繼承FilterAttribute抽象類,實現IAcionFilter接口和IResultFilter接口。

反編譯代碼以下:

不難看出,ActionFilterAttribute共有四個虛方法和一個可被繼承構造函數,而四個虛方法,分別是IAcionFilter接口和IResultFilter方法簽名的原型。

四個虛方法,在上面咱們已經分析過,這裏就不分析了,重點分析一下這四個方法的執行順序:

=》Request  ip=>Route(路由器尋找具體Controller和action)=>執行action上面的特性=》OnActionExecutiong=》執行方法=》OnActionExecuted=》OnResultExecuting=》執行操做結果=》OnResultExecuted=》將執行結果最終Responce給瀏覽器。

 源碼:

 public class ExeOrderTestAttribute:ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            Log("OnActionExecuted", filterContext.RouteData);
            base.OnActionExecuted(filterContext);
        }
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            Log("OnActionExecuting", filterContext.RouteData);
            base.OnActionExecuting(filterContext);
        }
        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            Log("OnResultExecuted", filterContext.RouteData);
            base.OnResultExecuted(filterContext);
        }
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            Log("OnResultExecuting", filterContext.RouteData);
            base.OnResultExecuting(filterContext);
        }
        private void Log(string methodName, RouteData routeData)
        {
            var controllerName = routeData.Values["controller"];
            var actionName = routeData.Values["action"];
            var message = String.Format("{0} controller: {1} action: {2}", methodName, controllerName, actionName);
            Debug.WriteLine(message, "ASP.NET MVC Filter ExecuteOrder");
        }
    }

 

 (三)其餘類

從上面的繼承圖中能夠看出,ASP.NET MVC過濾機制,處理定義接口,抽象類外,還有一些其餘基礎類,比較關鍵的類有:OutputCacheAttribute,ValidateInpuntAttribute,AuthorizeAttribute和ValidateAntiForgeryTokenAttribute。

1.OutputCacheAttribute 

該類主要是解決Cache問題,感興趣的,能夠看看淺談緩存技術在ASP.NET中的運用 ,這裏不累述。

2.ValidateInpuntAttribute 和ValidateAntiForgeryTokenAttribute

主要解決表單驗證問題,如防止漏洞注入,JS注入等問題。

3.AuthorizeAttribute

該類主要解決資源受權問題,也就是平時你們所說的權限管等問題,是很是重要的一個類,所以將在本篇文章的第二部分單獨講解。

 

二   MVC框架受權機制

ASP.NET MVC框架經過AuthorizeAttribute類實現資源的權限控制訪問。

咱們先來經過反彙編看看AuthorizeAttribute。

  1 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=true)]
  2 public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
  3 {
  4     // Fields
  5     private string _roles;
  6     private string[] _rolesSplit = new string[0];
  7     private static readonly char[] _splitParameter = new char[] { ',' };
  8     private readonly object _typeId = new object();
  9     private string _users;
 10     private string[] _usersSplit = new string[0];
 11 
 12     // Methods
 13     protected virtual bool AuthorizeCore(HttpContextBase httpContext)
 14     {
 15         if (httpContext == null)
 16         {
 17             throw new ArgumentNullException("httpContext");
 18         }
 19         IPrincipal user = httpContext.User;
 20         if (!user.Identity.IsAuthenticated)
 21         {
 22             return false;
 23         }
 24         if ((this._usersSplit.Length != 0) && !this._usersSplit.Contains<string>(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
 25         {
 26             return false;
 27         }
 28         if ((this._rolesSplit.Length != 0) && !this._rolesSplit.Any<string>(new Func<string, bool>(user.IsInRole)))
 29         {
 30             return false;
 31         }
 32         return true;
 33     }
 34 
 35     private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
 36     {
 37         validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context));
 38     }
 39 
 40     protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext)
 41     {
 42         filterContext.Result = new HttpUnauthorizedResult();
 43     }
 44 
 45     public virtual void OnAuthorization(AuthorizationContext filterContext)
 46     {
 47         if (filterContext == null)
 48         {
 49             throw new ArgumentNullException("filterContext");
 50         }
 51         if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
 52         {
 53             throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
 54         }
 55         if (!filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) && !filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true))
 56         {
 57             if (this.AuthorizeCore(filterContext.HttpContext))
 58             {
 59                 HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
 60                 cache.SetProxyMaxAge(new TimeSpan(0L));
 61                 cache.AddValidationCallback(new HttpCacheValidateHandler(this.CacheValidateHandler), null);
 62             }
 63             else
 64             {
 65                 this.HandleUnauthorizedRequest(filterContext);
 66             }
 67         }
 68     }
 69 
 70     protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
 71     {
 72         if (httpContext == null)
 73         {
 74             throw new ArgumentNullException("httpContext");
 75         }
 76         if (!this.AuthorizeCore(httpContext))
 77         {
 78             return HttpValidationStatus.IgnoreThisRequest;
 79         }
 80         return HttpValidationStatus.Valid;
 81     }
 82 
 83     internal static string[] SplitString(string original)
 84     {
 85         if (string.IsNullOrEmpty(original))
 86         {
 87             return new string[0];
 88         }
 89         return original.Split(_splitParameter).Select((<>c.<>9__19_0 ?? (<>c.<>9__19_0 = new Func<string, <>f__AnonymousType1<string, string>>(<>c.<>9.<SplitString>b__19_0)))).Where((<>c.<>9__19_1 ?? (<>c.<>9__19_1 = new Func<<>f__AnonymousType1<string, string>, bool>(<>c.<>9.<SplitString>b__19_1)))).Select((<>c.<>9__19_2 ?? (<>c.<>9__19_2 = new Func<<>f__AnonymousType1<string, string>, string>(<>c.<>9.<SplitString>b__19_2)))).ToArray<string>();
 90     }
 91 
 92     // Properties
 93     public string Roles
 94     {
 95         get
 96         {
 97             return (this._roles ?? string.Empty);
 98         }
 99         set
100         {
101             this._roles = value;
102             this._rolesSplit = SplitString(value);
103         }
104     }
105 
106     public override object TypeId
107     {
108         get
109         {
110             return this._typeId;
111         }
112     }
113 
114     public string Users
115     {
116         get
117         {
118             return (this._users ?? string.Empty);
119         }
120         set
121         {
122             this._users = value;
123             this._usersSplit = SplitString(value);
124         }
125     }
126 
127     // Nested Types
128     [Serializable, CompilerGenerated]
129     private sealed class <>c
130     {
131         // Fields
132         public static readonly AuthorizeAttribute.<>c <>9 = new AuthorizeAttribute.<>c();
133         public static Func<string, <>f__AnonymousType1<string, string>> <>9__19_0;
134         public static Func<<>f__AnonymousType1<string, string>, bool> <>9__19_1;
135         public static Func<<>f__AnonymousType1<string, string>, string> <>9__19_2;
136 
137         // Methods
138         internal <>f__AnonymousType1<string, string> <SplitString>b__19_0(string piece)
139         {
140             return new { piece = piece, trimmed = piece.Trim() };
141         }
142 
143         internal bool <SplitString>b__19_1(<>f__AnonymousType1<string, string> <>h__TransparentIdentifier0)
144         {
145             return !string.IsNullOrEmpty(<>h__TransparentIdentifier0.trimmed);
146         }
147 
148         internal string <SplitString>b__19_2(<>f__AnonymousType1<string, string> <>h__TransparentIdentifier0)
149         {
150             return <>h__TransparentIdentifier0.trimmed;
151         }
152     }
153 }
154 
155  
156 Collapse Methods
157  
View Code

經過反彙編,得出以下結論:

1.提供四個虛方法OnAuthorization(AuthorizationContext filterContext),AuthorizeCore(HttpContextBase httpContext),HandleUnauthorizedRequest(AuthorizationContext filterContext)和OnCacheAuthorization(HttpContextBase httpContext)。

 四個方法做用和關係是怎樣的呢

OnAuthorization表示請求過程時身份驗證,AuthorizeCore表示支持用戶自定義身份驗證,HandleUnauthorizeRequest表示當AuthorizeCore方法驗證失敗時,執行的操做,OnCacheAuthorization表示模塊緩存權限。

(一) ASP.NET MVC 基架提供的驗證

只需在須要驗證的資源生加上[Authorize]特性便可。

1   [Authorize]
2   public ActionResult Index()
3   {
4      return View(); ;
5   }

(二)  實現自定義驗證機制

當未給Index()  action添加驗證限制時,匿名用戶名能直接訪問 /Default/Index

當給Index()  action添加驗證限制時,匿名用戶名不能直接訪問 /Default/Index,而被強制重定型到登錄頁面,要求用戶登錄。

(三) ASP.NET MVC驗證級別

ASP.NET MVC提供了四種基本驗證模式:匿名,全局,控制器和Action

 

1.匿名

1 public class DefaultController : Controller
2     {
3         [AllowAnonymous]
4         public ActionResult Index()
5         {
6             return View();
7         }
8     }

2.action

1 public class DefaultController : Controller
2     {
3         [CustomAuthorize]
4         public ActionResult Index()
5         {
6             return View();
7         }
8     }

3.Controller

1 [CustomAuthorize]
2     public class DefaultController : Controller
3     {
4         public ActionResult Index()
5         {
6             return View();
7         }
8     }

4.全局

1 public class FilterConfig
2     {
3         public static void RegisterGlobalFilters(GlobalFilterCollection filters)
4         {
5             filters.Add(new CustomAuthorizeAttribute());//給自定義驗證註冊
6             filters.Add(new HandleErrorAttribute());
7         }
8     }

擴展,當添加多個驗證時,程序時如何執行的?通古Order值順序執行

1 [Filter1(Order = 3)]
2 [Filter2(Order = 2)]
3 [Filter3(Order = 1)]
4 public ActionResult Index()
5 {
6     return View(); ;
7 }

 三  總結

本篇文章主要從ASP.NET MVC框架設計角度,運用PD工具,經過UML分析ASP.NET MVC是如何實現資源過濾,如何實現權限控制等功能的,更細粒度的技術文章,在後續博文中更新。

相關文章
相關標籤/搜索