• Asp.Net MVC<五>:过滤器


    ControllerActionInvoker在执行过程中除了利用ActionDescriptor完成对目标Action方法本身的执行外,还会执行相关过滤器(Filter)。过滤器采用AOP的设计,它使我们可以将一些非业务的逻辑在相应的过滤器中实现,并以一种横切的方式应用到对应的Action方法上。

    根据用途和执行时机的不同,ASP.NET MVC提供的过滤器可分为6种

    1. AuthenticationFilter
    2. AuthorizationFilter
    3. ActionFilter
    4. ExceptionFilter
    5. ResultFilter
    6. OverrideFilter  :mvc5新增的一种特殊过滤器,它用于屏蔽应用在外围的过滤器。

    主要对象

    Filter

    一个Filter对象就是对一个过滤器的封装。

       1. Instance属性获取被封装的过滤器对象,Order决定过滤器的执行优先级,Scope决定应用范围。

       2. 多个同类过滤器的执行顺序 :先比较Order,值较小的先执行,Order相同则比对Scope ,Scope的执行顺序为First->Global->Controller->Action->Last

    public enum FilterScope
    {
        //
        // 摘要:
        //     Specifies first.
        First = 0,
        //
        // 摘要:
        //     Specifies an order before System.Web.Mvc.FilterScope.Controller and after System.Web.Mvc.FilterScope.First.
        Global = 10,
        //
        // 摘要:
        //     Specifies an order before System.Web.Mvc.FilterScope.Action and after System.Web.Mvc.FilterScope.Global.
        Controller = 20,
        //
        // 摘要:
        //     Specifies an order before System.Web.Mvc.FilterScope.Last and after System.Web.Mvc.FilterScope.Controller.
        Action = 30,
        //
        // 摘要:
        //     Specifies last.
        Last = 100
    }

    IFilterProvider

    用于获取Filer对象。有三种原生的FilterProvider:

    FilterAttributeFilterProvider

    用于获取通过特性注册的过滤器

    ControllerInstanceFilterProvider

    Controller本身就是一个过滤器,ControllerInstanceFilterProvider获取相应的Controller对象,并以此创建Filter对象。这个过滤器的优先级最高,会被最先执行。

    GlobalFilterCollection

    用于注册全局性的过滤器,并实现了IFilterProvider接口。

    FilterProviders

    用于提供Filter的FilterProvider通过静态类型FilterProviders注册。

    FilterInfo

    当ControllerActionInvoker被调用的时候,它会利用静态类型FilterProviders得到所有注册的FilterProvider,并利用它们根据当前的ControllerContext和ActionDescriptor对象得到所有的Filter。然后根据其Instance属性表示的过滤器类型将它们分组,最后得到一个具有如下定义的FilterInfo对象。

    public class FilterInfo
    {
        public FilterInfo();
    
        public FilterInfo(IEnumerable<Filter> filters);
    
        public IList<IActionFilter> ActionFilters { get; }
    
        public IList<IAuthenticationFilter> AuthenticationFilters { get; }
    
        public IList<IAuthorizationFilter> AuthorizationFilters { get; }
    
        public IList<IExceptionFilter> ExceptionFilters { get; }
    
        public IList<IResultFilter> ResultFilters { get; }
    }
    

      

    ReflectedControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(typeof(HomeController));
    ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(ControllerContext, "DemoAction");
    IEnumerable<Filter> filters = FilterProviders.Providers.GetFilters(ControllerContext, actionDescriptor);
    

    ps: 当以不同的Scope注册了多个AllowMultiple属性为false的某FilterAttribute类型的过滤器时,最终有效的是依执行顺序排在最后的那一个。

    AuthenticationFilter

    AuthenticationFilter用于在目标Action方法执行之前实施身份认证。采用的是“质询——应答(Chanllenge - Response)”的形式。认证方发出质询要被认证方提供用户凭证,而被认证方则提供相应凭证作为应答。

    public interface IAuthenticationFilter
    {
        //对请求实施认证
        void OnAuthentication(AuthenticationContext filterContext);
        //将相应的认证质询发给请求者
        void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
    }
    

      

    两个相关上下文对象

    //
    // 摘要:
    //     Represents an authentication context containing information for performing authentication.
    public class AuthenticationContext : ControllerContext
    {
        public AuthenticationContext();
        public AuthenticationContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IPrincipal principal);
    
        //
        // 摘要:
        //     Gets or sets the action descriptor.
        //
        // 返回结果:
        //     The action methods associated with the authentication
        public ActionDescriptor ActionDescriptor { get; set; }
        //
        // 摘要:
        //     Gets or sets the currently authenticated principal.
        //
        // 返回结果:
        //     The security credentials for the authentication.
        public IPrincipal Principal { get; set; }
        //
        // 摘要:
        //     Gets or sets the error result, which indicates that authentication was attempted
        //     and failed.
        //
        // 返回结果:
        //     The authentication result.
        public ActionResult Result { get; set; }
    }
    

      

    //
    // 摘要:
    //     Represents an authentication challenge context containing information for executing
    //     an authentication challenge.
    public class AuthenticationChallengeContext : ControllerContext
    {
        public AuthenticationChallengeContext();
        //
        // 摘要:
        //     Initializes a new instance of the System.Web.Mvc.Filters.AuthenticationChallengeContext
        //     class.
        //
        // 参数:
        //   controllerContext:
        //     The controller context.
        //
        //   actionDescriptor:
        //     The action methods associated with the challenge.
        //
        //   result:
        //     The challenge response.
        public AuthenticationChallengeContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor, ActionResult result);
    
        //
        // 摘要:
        //     Gets or sets the action descriptor.
        //
        // 返回结果:
        //     The action descriptor associated with the challenge.
        public ActionDescriptor ActionDescriptor { get; set; }
        //
        // 摘要:
        //     Gets or sets the action result to execute.
        //
        // 返回结果:
        //     The challenge response.
        public ActionResult Result { get; set; }
    }
    

    执行

    身份认证是请求处理的第一步,所以AuthenticationFilter是最先被执行的过滤器。

    所有过滤器的执行都是由ActionInvoker来驱动的,默认采用AsyncControllerActionInvoker对象。它派生自ControllerActionInvoker。

      方法执行之前:

    1. 如果多个AuthenticationFilter同时应用到目标方法上,则依据相应的Order和Scope属性对它们进行排序。
    2. 根据当前ControllerContext、描述目标方法的ActionDescriptor对象及原始的Principal(对应HttpContext的User属性)创建AuthenticationContext对象。
    3. 将AuthenticationContext对象作为参数调用每个AuthenticationFilter的OnAuthentication方法实施认证。这里可以直接设置AuthenticationContext的ActionResult属性 ,则它会直接用于响应当前请求。

     方法执行之后:

    1. 执行的结果总是体现为一个ActionResult对象。ControllerActionInvoker对象会根据ControllerContext,描述目标方法的ActionDescriptor对象 和这个ActionResult对象创建一个AuthenticationChallengeContext对象。
    2. 将AuthenticationChallengeContext对象作为参数逆序调用每个AuthenticationFilter的OnAuthenticationChallenge方法。这个AuthenticationChallengeContext对象的ActionResult属性返回的ActionResult对象将被用于响应当前请求。

     在整个AuthenticationFilter链的执行过程中,如果某个AuthenticationFilter对象的OnAuthentication方法执行时对作为参数的AuthenticationContext对象的ActionResult属性做了相应设置,则整个“AuthenticationFilter链”的执行立即中止,指定的这个ActionResult对象将用于响应当前请求。如果在执行过程中对AuthenticationContext对象的Principal属性做了相应的设置,该属性值将会作为当前HttpContext和当前线程的Principal。

    自定义AuthenticateAttribute 

    public class AuthenticateAttribute : FilterAttribute, IAuthenticationFilter
    {
        public const string AuthorizationHeaderName = "Authorization";
        public const string WwwAuthenticationHeaderName = "WWW-Authenticate";
        public const string BasicAuthenticationScheme = "Basic";
        private static Dictionary<string, string> userAccounters;
    
        static AuthenticateAttribute()
        {
            userAccounters = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            userAccounters.Add("Foo", "Password");
            userAccounters.Add("Bar", "Password");
            userAccounters.Add("Baz", "Password");
        }
    
        public void OnAuthentication(AuthenticationContext filterContext)
        {
            IPrincipal user;
            if (this.IsAuthenticated(filterContext, out user))
            {
                filterContext.Principal = user;
            }
            else
            {
                this.HandleUnauthenticatedRequest(filterContext);
            }
        }
    
        protected virtual AuthenticationHeaderValue GetAuthenticationHeaderValue(AuthenticationContext filterContext)
        {
            string rawValue = filterContext.RequestContext.HttpContext.Request.Headers[AuthorizationHeaderName];
            if (string.IsNullOrEmpty(rawValue))
            {
                return null;
            }
            string[] split = rawValue.Split(' ');
            if (split.Length != 2)
            {
                return null;
            }
            return new AuthenticationHeaderValue(split[0], split[1]);
        }
    
        protected virtual bool IsAuthenticated(AuthenticationContext filterContext, out IPrincipal user)
        {
            user = filterContext.Principal;
            if (null != user & user.Identity.IsAuthenticated)
            {
                return true;
            }
    
            AuthenticationHeaderValue token = this.GetAuthenticationHeaderValue(filterContext);
            if (null != token && token.Scheme == BasicAuthenticationScheme)
            {
                string credential = Encoding.Default.GetString(Convert.FromBase64String(token.Parameter));
                string[] split = credential.Split(':');
                if (split.Length == 2)
                {
                    string userName = split[0];
                    string password;
                    if (userAccounters.TryGetValue(userName, out password))
                    {
                        if (password == split[1])
                        {
                            GenericIdentity identity = new GenericIdentity(userName);
                            user = new GenericPrincipal(identity, new string[0]);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    
        protected virtual void HandleUnauthenticatedRequest(AuthenticationContext filterContext)
        {
            string parameter = string.Format("realm="{0}"", filterContext.RequestContext.HttpContext.Request.Url.DnsSafeHost);
            AuthenticationHeaderValue challenge = new AuthenticationHeaderValue(BasicAuthenticationScheme, parameter);
            filterContext.HttpContext.Response.Headers[WwwAuthenticationHeaderName] = challenge.ToString();
            filterContext.Result = new HttpUnauthorizedResult();
        }
    
        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) { }
    }
    

      

    AuthorizationFilter

    AuthorizationFilter将会在所有AuthenticationFilter执行结束后执行,因为授权检验要在认证之后才有意义。

    public interface IAuthorizationFilter
    {
        //
        // 摘要:
        //     Called when authorization is required.
        //
        // 参数:
        //   filterContext:
        //     The filter context.
        void OnAuthorization(AuthorizationContext filterContext);
    }
    

      

    public class AuthorizationContext : ControllerContext
    {
        public AuthorizationContext();
        //
        // 摘要:
        //     Initializes a new instance of the System.Web.Mvc.AuthorizationContext class using
        //     the specified controller context.
        //
        // 参数:
        //   controllerContext:
        //     The context within which the result is executed. The context information includes
        //     the controller, HTTP content, request context, and route data.
        [Obsolete("The recommended alternative is the constructor AuthorizationContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor).")]
        public AuthorizationContext(ControllerContext controllerContext);
        //
        // 摘要:
        //     Initializes a new instance of the System.Web.Mvc.AuthorizationContext class using
        //     the specified controller context and action descriptor.
        //
        // 参数:
        //   controllerContext:
        //     The context in which the result is executed. The context information includes
        //     the controller, HTTP content, request context, and route data.
        //
        //   actionDescriptor:
        //     An object that provides information about an action method, such as its name,
        //     controller, parameters, attributes, and filters.
        public AuthorizationContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
    
        //
        // 摘要:
        //     Provides information about the action method that is marked by the System.Web.Mvc.AuthorizeAttribute
        //     attribute, such as its name, controller, parameters, attributes, and filters.
        //
        // 返回结果:
        //     The action descriptor for the action method that is marked by the System.Web.Mvc.AuthorizeAttribute
        //     attribute.
        public virtual ActionDescriptor ActionDescriptor { get; set; }
        //
        // 摘要:
        //     Gets or sets the result that is returned by an action method.
        //
        // 返回结果:
        //     The result that is returned by an action method.
        public ActionResult Result { get; set; }
    }
    

    AuthorizeAtrribute

    标记该Action只有被认证用户才能访问 ,可以显式地对Users和Roles属性进行设置,限定范围。

    授权失败则返回状态为401的响应。

     对比 PrincipalPermissionAttribute特性

    PrincipalPermissionAttribute通过代码访问安全检验实现对方法调用的授权。

    [PrincipalPermission(SecurityAction.Demand,Name ="foo", Role = @"BUILTIN/Administrators")] 标识必须是账号为foo或拥有"BUILTIN/Administrators"角色的用户才能访问

    同时它们的授权策略也不一样,PrincipalPermission 是Or的关系,如果存在多个PrincipalPermission属性,只要满足一个就可以。而Authorize是And的关系,必须同时满足。

    RequestHttpsAttribute

    限制必须以https请求的方式访问目标Action,

    如果当前是一个Get请求,但并不是采用https的,则会自动跳转替换url为https方式的访问形式,对于非Get方式的请求则会调用HandlerNonHttpsRequest方法,可以重写这个方法。

    ValidateInputAttribute

    用于拦截XSS攻击等不合法的请求内容,

    HttpRequestBase具有一个ValidateInput的方法用于验证请求的输入,

    ControllerBase具有一个布尔属性ValidateRequest 用于标记是否需要对请求输入进行验证,这个属性的默认值是True。

    ValidateInputAttribute就是通过改变Controller的ValidateRequest 属性的取值来开启或关闭验证

    对比AllowHtmlAttribute属性

    AllowHtmlAttribute仅针对容器成员的某个数据成员,而ValidateInputAttribute针对整个请求。

    ValidateAntiForgeryTokenAttribute

    ValidateAntiForgeryTokenAttribute结合HtmlHelper的AntiForgeryToken方法用于防备CSRF攻击。

    当在View中调用HtmlHelper的AntiForgeryToken方法时,它会创建一个称为“防伪令牌(AntiForgeryToken)”的字符串,并返回一个类型为hidden的<input>元素对应的html,同时设置一个HttpOnly标记的Cookie,Cookie名称与当前请求的应用路径有关,Cookie值(一个AntiForgeryData对象)则经过加密,由这个Cookie值可以计算得到防伪令牌。

    ChildActionOnlyAttribute

    标记某action为ChildAction,即不能以Http请求的方式被直接调用,仅仅希望它在某个View中被调用以生成组成页面某个部分的Html。

    ActionFiler

    Context:

    AsyncTimeoutAttribute, NoAsyncTimeoutAttribute

    ExceptionFilter

    用于处理包括目标Action方法在内的整个ActionFilter链执行过程中抛出的异常,

    1. ExceptionFilter链执行顺序是反向的,即优先级越高执行顺序越靠后。

    2. 将ExceptionContext的ExceptionHandled设置为true ,并不会阻止后续ExceptionFilter的执行

    3. 如果ExceptionFilter在执行OnException的过程中出现异常,整个ExceptionFilter链的执行将立即中止,并且该异常被直接抛出来。

    HandlerErrorAttribute

    属性View和Master表示作为错误页面的View名称和对应的布局文件名,默认值分别为"Error"和空字符串。会创建一个HandlerErrorInfo对象作为Model,传递给View。

    默认的异常处理注册

    只有在当前HttpContext的IsCustomErrorEnabled属性是True的情况下HandleErrorAttribute才会真正被用于处理抛出的异常,

    Web.config中: <system.web><customErrors mode="On|Off|RemoteOnly"/></system.web>

    ResultFilter

    不管目标Action方法是否有返回值,不论它返回一个怎样的对象,ControllerActionInvoker在完成了目标Action方法后总会生成一个ActionResult对象来对请求进行响应。在执行这个ActionResult的前后,应用在目标Action方法上的ReslutFilter会被执行。

    ResultExecutedContext中的Exception是ActionResult执行过程中抛出的异常

    OverrideFilter

    Filter通过Scope属性表示被封装的过滤器的应用范围:全局注册的过滤器会自动应用到所有Controller类型上,HttpController上注册的过滤器则自动应用到定义在其中的所有Action上。

    如果某个Action方法不需要这些外围注册的过滤器,则需要使用OverrideFilter这种特殊过滤器了。

    [OverrideActionFilters]
    [OverrideAuthentication]
    [OverrideAuthorization]
    [OverrideExceptionFilters]
    [OverrideResultFilters]

  • 相关阅读:
    基于 mysql 异步驱动的非阻塞 Mybatis【待验证】
    Hive SQL优化方式及使用技巧
    使用Guava-RateLimiter限流控制qps
    hive 时间戳函数之unix_timestamp,from_unixtime
    Hive实现自增列的两种方法
    shell 下 urlencode/urldecode 编码/解码的方法
    awk使用shell变量,shell获取awk中的变量值
    shell脚本删除远程过期文件
    linux下多进程同时操作文件
    hive学习----Hive表的创建
  • 原文地址:https://www.cnblogs.com/wj033/p/5877749.html
Copyright © 2020-2023  润新知