欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-05 20:31:59
一.概述 本篇详细了解一下asp.net core filters,filter叫"筛选器"也叫"过滤器",是请求处理管道中的特定阶段之前或之后运行代码。filter用于处理横切关注点。 横切关注点的示例包括:错误处理、缓存、配置、授权和日志记录。 filter可以避免重复代码,通过Attribut ......

一.概述

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

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

   [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表的实现。

  下面是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  授权筛选器

    resource filters       资源筛选器

    action filters            操作筛选器 (razor pages 中使用 ipagefilter 和 iasyncpagefilter)

    exception filters      异常筛选器

    result filters            结果筛选器

    每种filter 类型都在filter 管道中的不同阶段执行,当用户请求进来时,经过filter管道,执行filter的阶段顺序如下所示:

asp.net core系列 68  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) 结果被视为失败。

 

 

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

  参考资料:

    

    官方示例代码