asp.net core系列 68 Filter管道过滤器

一.概述

  本篇详细了解一下asp.net core filters,filter叫"筛选器"也叫"过滤器",是请求处理管道中的特定阶段以前或以后运行代码。filter用于处理横切关注点。 横切关注点的示例包括:错误处理、缓存、配置、受权和日志记录。 filter能够避免重复代码,经过Attribute特性来实现filter过滤。Filter适应于 Razor Pages,  API controllers,  mvc controllers。filter基类是IFilterMetadata 接口,该接口只是用来标记是一个filter过滤器。git

  前段时间在项目中实现了IAsyncAuthorizationFilter接口对用户访问controller或action进行了受权,在OnAuthorizationAsync方法中使用context.Result可以使管道短道。IAsyncAuthorizationFilter是属于受权过滤器中的一种。勿在受权过滤器内抛出异常,这是由于所抛出的异常不会被处理。下面是简要的实现受权代码:github

   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class PermissionFilter : Attribute,IAsyncAuthorizationFilter
  {
    public   Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
                IIdentity user = context.HttpContext.User.Identity;
                if (!user.IsAuthenticated)
                {
            //跳转到登陆页
              context.Result = new LocalRedirectResult(url);
             return Task.CompletedTask;
             }
 
         //根据当前用户,判断当前访问的action,没有权限时返回403错误
         context.Result = new ForbidResult();
            
             return Task.CompletedTask;
     }
    }

  在官方文档中说到:"自定义受权筛选器Filter须要自定义受权框架, 建议配置受权策略或编写自定义受权策略,而不是编写自定义Filter筛选器"。缓存

  这里的意思是说,若是在项目中不使用asp.net core自带的identity,那么须要自定义受权框架,也就是须要本身创建一套用户权限表。 若是使用了identity建议配置受权策略或编写自定义受权策略。若是不用identity本身创建用户权限表,那么就能够编写自定义Filter筛选器。我在项目开发中是本身创建了用户权限表没有用identity。由于使用identity表还须要扩展字段,并且与EF core结合紧密,若是不使用EF core须要重写访问identity表的实现。mvc

  下面是identity与ef core相关的代码: 框架

   services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

   -- TContext必须是DbContext类型
    public static IdentityBuilder AddEntityFrameworkStores<TContext>(this IdentityBuilder builder) where TContext : DbContext

 

二.Filter 筛选器类型

    Authorization filters  受权筛选器asp.net

    Resource filters       资源筛选器异步

    Action filters            操做筛选器 (Razor Pages 中使用 IPageFilter 和 IAsyncPageFilter)ide

    Exception filters      异常筛选器ui

    Result filters            结果筛选器this

    每种Filter 类型都在Filter 管道中的不一样阶段执行,当用户请求进来时,通过Filter管道,执行Filter的阶段顺序以下所示:

    上面每种Filter 类型都有本身的接口,都同时支持同步和异步实现,上面的受权示例就是一个异步实现受权筛选器IAsyncAuthorizationFilter。Filter 接口或直接或间接实现了IFilterMetadata接口,IFilterMetadata接口只是用来标记是一个Filter 。

 

三.filter筛选器做用域

  (1) 将 attribute特性应用在 action上。

  (2) 将 attribute特性应用在 controller上。

  (3) 全局筛选器应用在controller和action上

    下面使用全局筛选器,使用MvcOptions.Filters 集合,添加三个筛选器,以下面的代码所示:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader",
            "Result filter added to MvcOptions.Filters"));         // An instance
        options.Filters.Add(typeof(MySampleActionFilter));         // By type
        options.Filters.Add(new SampleGlobalActionFilter());       // An instance
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
//实现了内置筛选器属性
public class AddHeaderAttribute : ResultFilterAttribute
//实现了操做筛选器
public class MySampleActionFilter : IActionFilter
//实现了操做筛选器
public class SampleGlobalActionFilter : IActionFilter

 

四.内置筛选器Attribute属性

    下面都是filter内置的属性类,须要去实现这些抽象属性类。

      ActionFilterAttribute
      ExceptionFilterAttribute
      ResultFilterAttribute
      FormatFilterAttribute
      ServiceFilterAttribute
      TypeFilterAttribute

  下面一个示例是为响应添加标头,开发人员来实现ResultFilterAttribute抽象类:

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string _value;

    public AddHeaderAttribute(string name, string value)
    {
        _name = name;
        _value = value;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add( _name, new string[] { _value });
        base.OnResultExecuting(context);
    }
}

     经过使用属性,筛选器可接收参数,将 AddHeaderAttribute 添加到控制器或操做方法,并指定 HTTP 标头的名称和值,以下所示:

        [AddHeader("Author", "Steve Smith @ardalis")]
        public IActionResult Hello(string name)
        {
            return Content($"Hello {name}");
        }
    

 

五.Filter三种依赖关系注入

    (1)ServiceFilterAttribute
    (2)TypeFilterAttribute
    (3)在属性上实现 IFilterFactory。

  5.1 ServiceFilterAttribute演示

    下面是在 ConfigureServices 中注册服务筛选器实现类型,内置的ServiceFilterAttribute会从DI 检索筛选器实例。

public class AddHeaderResultServiceFilter : IResultFilter
{
    private ILogger _logger;
    public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var headerName = "OnResultExecuting";
        context.HttpContext.Response.Headers.Add(
            headerName, new string[] { "ResultExecutingSuccessfully" });
        _logger.LogInformation($"Header added: {headerName}");
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // Can't add to headers here because response has started.
    }
}

     在如下代码中,AddHeaderResultServiceFilter 将添加到 DI 容器中:

    services.AddScoped<AddHeaderResultServiceFilter>();

    在如下代码中,经过ServiceFilter 属性,将从 DI 中检索 AddHeaderResultServiceFilter 筛选器的实例:

[ServiceFilter(typeof(AddHeaderResultServiceFilter))]
public IActionResult Index()
{
    return View();
}

 

六. 各类筛选器介绍

  6.1 Authorization filters 

    是筛选器管道中第一个运行的筛选器。是控制对Action方法的访问。

     在Action以前执行的方法,没有在Action以后执行的方法。

       注意:不要在受权筛选器中引起异常

    场景:

      若是使用identity,可用配置受权策略或编写自定义受权策略。详情查看identity部分。

      若是不使用identity,可编写自定义筛选器。

 

  6.2 Resource filters

    实现 IResourceFilter 或 IAsyncResourceFilter 接口。

    它执行会覆盖筛选器管道的绝大部分。

    它在受权筛选器以后运行。

    场景:

      能够防止模型绑定访问表单数据。

      用于上传大型文件,以防止表单数据被读入内存。

 

  6.3 Action filters

    实现 IActionFilter 或 IAsyncActionFilter 接口。

    它围绕着Action方法的执行。

    它方法中有个重要属性ActionArguments ,用于读取action的输入参数。

    场景:

      能够在该接口的OnActionExecuting方法中进行验证模型状态(ModelState.IsValid),若是状态无效,则返回错误(这个场景颇有用)。

 

  6.4 Exception filters

    实现 IExceptionFilter 或 IAsyncExceptionFilter。

    它没有以前和以后的事件,

    可实现该接口的 OnException 或 OnExceptionAsync方法。

    处理 Razor 页面或控制器建立、模型绑定、操做筛选器或操做方法中发生的未经处理的异常

    若要处理异常(再也不throw),请将 ExceptionHandled 属性设置为 true。

    场景:

      实现常见的错误处理策略。

      很是适合捕获发生在action中的异常。

 

  6.5 Result filters

    实现 IResultFilter 或 IAsyncResultFilter 或 IAlwaysRunResultFilter 或 IAsyncAlwaysRunResultFilter

    它执行围绕着action结果的执行。当异常筛选器处理异常时,不执行结果筛选器

    若是在 IResultFilter.OnResultExecuting 中引起异常,则会致使:

      (1) 阻止action结果和后续筛选器的执行。

      (2) 结果被视为失败。

 

 

  更详细的资料参考官网文档,后续在实际项目中应用到的筛选器,将会再本篇继续补上。

  参考资料:

    官方文档

    官方示例代码

相关文章
相关标签/搜索