• 【ASP.NET MVC系列】浅谈ASP.NET MVC资源过滤和授权


    最近比较忙,博客很久没更新了,很多博友问何时更新博文,因此,今天就花了点时间,写了本篇文章,但愿大家喜欢。

    本篇文章不适合初学者,需要对ASP.NET MVC具有一定基础。

    本篇文章主要从ASP.NET MVC 基架角度去分析MVC框架是如何实现资源过滤,资源授权,感兴趣的,欢迎阅读。

    相关文章,请参与ASP.NET MVC系列

    一 ASP.NET MVC框架验证机制

    为了更加透彻地了解MVC的过滤机制,我简要地画了如下UML图。

     下面,我们根据如上的UML图来简要分析一下。

    (一)MVC基架过滤机制根接口

    根接口:本文指在继承关系中的根节点,相当于类的祖宗对象Object。

    从上图中,很容易看出MVC过滤机制的根接口主要有六大类型接口:_Attribute,IMvcFilter,IActionFilter,IResultFilter,IExceptionFilter和IAuthorizationFilter。

    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是如何实现资源过滤,如何实现权限控制等功能的,更细粒度的技术文章,在后续博文中更新。

  • 相关阅读:
    14. HTML 列表(无序, 有序, 定义)
    13. HTML table
    12. HTML图像
    11. HTML链接
    10. HTML CSS
    learning java AWT Pannel
    learning AWT Jrame
    learning java 正则表达式
    learning java java.time相关类
    learning java Calendar类
  • 原文地址:https://www.cnblogs.com/wangjiming/p/8293978.html
Copyright © 2020-2023  润新知