AOP系列之Filter管道模型

一、前言

Filter 是延续 Asp.Net Mvc 的产物,同样保留了五种的Filter,分别是Authorization FilterResource FilterAction FilterException FilterResult Filter。通过不同的 Filter 可以有效处理一些共通的动作。

(一)Filter 介绍

  • Authorization Filter:优先级1;权限过滤器,通常在 Filter Pipleline 中首先执行,并用于决定当前客户端 Request 请求权限的身份授权验证
  • Resource Filter:优先级2;资源过滤器,通常在 Authorization 后面执行,同时在后面的其它过滤器完成后还会执行;作用于Api资源授权、缓存处理等一些可以性能原因的拦截,因为运行在模型绑定前,所以这里的操作都会影响模型绑定。
  • Action Filter:优先级3;方法过滤器,执行于 Action 方法前后,用于 Action 审计日志、传递参数和方法返回值的处理。
  • Exception Filter:优先级4;异常过滤器,被应用全局策略处理未处理的异常被写入响应体。
  • Result Filter:优先级5;返回值过滤器,可以执行于 Action 结果之前执行,且执行 Action 成功后执行,使用逻辑一般围绕 Action 入参的验证和格式化返回值。

(二)Filter 流程图

image

二、Filter 实现&场景应用

在开始写代码前需引用nuget包或包含的集成包 Microsoft.AspNetCore.Mvc.Abstractions 均可;下面我用异步的方式,继承相应过滤器实现对应功能,说这么多,还是看代码吧!

(一)Authorization Filter

权限过滤器,通过 Authorization Filter 可以实现复杂的 防篡改验证XsrfToken防伪令牌 等操作。具体代码如下:

    /// <summary>
    /// SB过滤器 - 权限
    /// </summary>
    public class SBAuthorizationFilterAttribute : Attribute, IAsyncAuthorizationFilter
    {
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {

            // 参数防篡改

            // 验证XsrfToken防伪令牌

            // ..

        }
    }

(二)Resource Filter

资源过滤器,通过 Resource Filter 可以进行 Api资源授权缓存处理 等复杂操作。具体代码如下:

    /// <summary>
    /// SB过滤器 - 资源
    /// </summary>
    public class SBResourceFilterAttribute : Attribute, IAsyncResourceFilter
    {
        public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
        {
            // 控制器实例化之前,执行的动作

            // 验证是否跳过Api资源授权

            // 缓存处理

            await next();
            
            // Action的Result Filter(befor)执行后再执行

        }
    }

(三)Action Filter

方法过滤器,执行于控制器方法的前后置动作,前置动作可以应用于 参数传递 ,后置动作可以应用于 Action审计日志 。具体代码如下:

    /// <summary>
    /// SB过滤器 - 方法
    /// </summary>
    public class SBActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {

            // Action执行前,执行的动作

            // 参数传递
            
            var result = await next();

            // Action的执行后,执行的动作

            // Action审计日志

        }
    }

(四)Exception Filter

异常过滤器,作用于全局的异常处理,当系统发生未捕获异常时会触发此过滤器进行处理,应用于 全局异常捕获异常日志处理 。具体代码如下:

    /// <summary>
    /// SB过滤器 - 全局异常
    /// </summary>
    public class SBExceptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {

            if (context.ExceptionHandled)//异常是否已处理
                return;

            // 异常处理
            context.Result = new ObjectResult(
                        new { code = "412", msg = "异常信息" });

            // 处理完告诉系统此异常已处理
            context.ExceptionHandled = true;
        }
    }

(五)Result Filter

返回值过滤器,执行于结果执行之前/之后,前置动作可以应用于 Dto模型验证 ,后置动作可以应用于 格式化返回值 。具体代码如下:

    /// <summary>
    /// SB过滤器 - 返回值
    /// </summary>
    public class SBResultFilter : IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {

            // 结果执行前,执行的动作

            // Dto模型验证

            var result = await next();

            // 结果执行后,执行的动作

            // 格式化返回值

        }
    }

三、Asp.Net Core 过滤器的注册方式

Asp.Net Core过滤器 分为两种注册方式 全局局部 ,根据过滤器的使用场景及需要我们可以选择不同的注册方式。

(一)全局注册

过滤器也区分作用于全局和局部之分,作用于全局就不需要局部(类、控制器等)每一个进行代码注册,相对方便非常多。具体代码如下:

        public void ConfigureServices(IServiceCollection services)
        {
            //...

            services.AddMvc(options => {
                options.Filters.Add<SBAuthorizationFilterAttribute>();
                options.Filters.Add<SBResourceFilterAttribute>();
                options.Filters.Add<SBActionFilter>();
                options.Filters.Add<SBExceptionFilter>();
                options.Filters.Add<SBResultFilter>();
            });

            //...
        }

(二)局部注册

场景假设几大过滤器中有个过滤器只想作用于局部作用,过滤器可能就需要局部注册 ServiceFilterTypeFilter
ps:几大过滤器没有继承 Attribute 不能使用特性的注册方式,想了解特性注册方式可以百度,暂时还没写。

ServiceFilterTypeFilter 的区别:

  • ServiceFilterTypeFilter 都实现了 IFilterFactory
  • ServiceFilter 需要对自定义的 Filter 进行注册,TypeFilter 不需要。
  • ServiceFilterFilter 生命周期源自于注册方式,而 TypeFilter 每次都会创建一个新的实例。

1. ServiceFilter 使用方式

控制器中具体代码如下:

    [ServiceFilter(typeof(SBAuthorizationFilterAttribute))]//过滤器注册到控制器中
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        // GET: api/Default
        [HttpGet]
        [ServiceFilter(typeof(SBAuthorizationFilterAttribute))]//过滤器注册到方法中
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }

注册服务中具体代码如下:

        public void ConfigureServices(IServiceCollection services)
        {
            //...

            services.AddMvc();

            // 注册过滤器服务,使用ServiceFilter 方式必须要注册 否则会报没有注册该服务的相关异常
            services.AddSingleton<SBAuthorizationFilterAttribute>();

            //...
        }

2. TypeFilter 使用方式

TypeFilter 的用法就比较方便,只要控制器或者方法注册即可。

    [TypeFilter(typeof(SBAuthorizationFilterAttribute))]//过滤器注册到控制器中
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        // GET: api/Default
        [HttpGet]
        [TypeFilter(typeof(SBAuthorizationFilterAttribute))]//过滤器注册到方法中
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }

四、Asp.Net Core 过滤器调用顺序

  • 全局->局部
  • Controller->Action
  • 先注册先调用

image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章