文档章节

包含在ASP.NET MVC中的过滤器

清山博客
 清山博客
发布于 2016/07/15 20:03
字数 3123
阅读 4
收藏 0

在深入研究如何编写过滤器之前,首先看看包含在ASP.NET MVC中的过滤器。

ASP.NET MVC包括了如下3种即开即用的动作过滤器:

Authorize:该过滤器用于限制对控制器或控制器动作的访问。

HandleError:该过滤器用来指定一个处理异常的动作,这个异常是从动作方法的内部抛出的。

OutputCache:该过滤器用来为动作方法提供输出的缓存。

接下来将依次深入讨论这3个过滤器。

1  Authorize

AuthorizeAttribute是包含在ASP.NET MVC中默认的授权过滤器。可以使用它来限制对动作方法的访问。将该特性运用到控制器上可以迅速将其运用到每个动作方法中。

在运用该过滤器时需要牢记如下内容:

在运用该特性时,可以指定一个逗号来划分角色(Role)或用户(User)的列表。如果指定了一个角色的列表,那么为了动作方法的执行,用户必须是其中一个角色中的成员。同样的,如果指定了一个用户的列表,那么当前用户的名称必须在该列表中。

为什么不使用已有的、构建在ASP.NET中的URL授权

保护使用了Web Forms的应用程序的常见方式是使用URL授权。例如,如果具有一个管理部分,而且希望将其限制为那些位于管理员(Admins)角色中的用户,那么可能会把所有管理页面都放在管理文件夹中并拒绝除位于管理员角色中以外的任何人访问子文件夹。

对于MVC而言,这种方法不会很好地运转,原因有两个:

请求不再映射到物理目录中。

进入到同一个控制器的路由可能不止一个。

对于MVC而言,理论上讲,是可以使用AdminController封装应用程序的管理功能,然后在web.config根文件中设置URL授权,进而阻止访问任何以/Admin开头的请求。然而,这并不是万无一失的,也有可能存在另外一个路由,它可能在不经意间映射到AdminController中。

例如,后面将会讨论的,如果决定切换默认路由中的{controller}和{action}的顺序,那么此时,/Index/Admin是默认的管理页面的URL,而且URL授权也不再阻止它。

安全性较好的一个方法是总是尽可能紧紧地将安全检查放到需要保护的对象上。虽然可能会在更高层次的堆栈上具有其他检查,但是最终希望保护的是实际的资源。在这种情况下,不希望依靠路由选择和URL授权来保护控制器;真正想要保护的是控制器自身。AuthorizeAttribute正好用于此用途。

如果没有指定任何角色或用户,那么为了调用动作方法,必须只验证当前的用户。这是阻止非验证用户访问特殊控制器动作的一个简单的方法。

如果用户试图访问运用了该特性的动作方法且在授权检查中失败,那么过滤器将引发服务器返回一个401 Unauthorized的HTTP状态代码。

对于启用了表单验证且在web.config中指定了注册URL的情形,ASP.NET将处理该响应代码并将用户重新引向注册页面。这是ASP.NET已有的行为,对于ASP.NET MVC也不是新鲜事物。

产品小组的话:

一开始,我们将PrincipalPermissionAttribute看作是保护控制器动作的一个可行的解决方案,但是碰到了很多问题。首先,在将其运用到类时,PrincipalPermissionAttribute将在安全检查失败而试图实例化Controller类时导致一个异常。因为我们希望当安全检查失败时可能会有其他过滤器运行(例如,日志记录过滤器),所以这并不是我们想要的行为。

其次,我们希望能控制产生的状态代码。而PrincipalPermissionAttribute只是抛出一个SecurityException。

下面看一个使用的简单示例。在下面的代码中,管理控制器只限制于Admins和SuperAdmins角色的成员。注意,角色是通过逗号隔开的。过滤器将忽略逗号之间的空白以允许提高在运用该特性时的可读性。


  
  1. [Authorize(Roles="Admins, SuperAdmins")]  
  2. public class AdminController  
  3. {  
  4.     //Only admins should see this.  
  5.     public ActionResult Index()   
  6.     {  
  7.       return View();  
  8.     }  
  9.      
  10.     //Only admins should see this.  
  11.     public ActionResult DeleteAllUsers()  
  12.     {  
  13.         //Thankfully, this is secured by the Authorize attribute.  
  14.     }  

在认真思考上述示例之后,本书作者认识到我们并不希望任何管理员或系统管理员(superadmin)能够调用DeleteAllUsers的动作。事实上,我们只信任由Phil完成该动作,所以这里运用了一个更为具体的授权,即只允许用户Phil来调用该动作。当运用了多个授权过滤器时,用户为了调用动作必须满足所有的授权过滤器。因此,在这种情况下,Phil必须同时是管理员(Admins)角色的成员也是系统管理员(SuperAdmins)角色的成员。

注意:

另一件需要注意的事情是,一般来说:甚至在类似情况下,使用角色而不是具体的用户名将更有意义。更好的方法可能是创建一个名为CanDeleteAllUsers的角色并将Phil添加到该角色中,然后运用一个指定了该角色的授权过滤器。


  
  1. [Authorize(Roles="Admins, SuperAdmins")]  
  2. public class AdminController  
  3. {  
  4.     //Only admins should see this.  
  5.     public ActionResult Index()   
  6.     {  
  7.       return View();  
  8.     }  
  9.      
  10.     //Only Phil should do this.  
  11.     [Authorize(Users="Phil")]  
  12.     public ActionResult DeleteAllUsers()  
  13.     {  
  14.         //…  
  15.     }  

在最后的示例中,切换到一个为个人用户提供用户管理的控制器中;不需要指定用户和角色。在这种情况下,控制器可能向所有通过验证的人打开大门。


  
  1. [Authorize]  
  2. public class UsersController  
  3. {  
  4.     public ActionResult ManageProfile()  
  5.     {  
  6.         //…  
  7.         return View();  
  8.     }  
  9. }
2.OutputCache

OutputCacheAttribute用来缓存动作方法的输出。该特性是到ASP.NET输出缓存功能内的连接,而且提供了在使用@OutputCache页面指令时得到的大部分相同的API和行为。本章后面将讨论两者之间微小的区别。

因为输出缓存是ASP.NET非常著名的功能,所以本节没有深入讨论缓存行为自身的细节,而是将注意力集中于MVC实现上。此时,可能会有一个问题,"为什么不在视图中只使用@OutputCache指令呢?"

对于MVC而言,首先在选中视图之前,执行控制器动作。因此,将输出缓存放到视图上,这实际上将缓存视图的输出,而动作方法自身将仍然在每个请求上执行,这样就否定了缓存输出的大部分优点。

通过将该特性运用到动作方法中,过滤器随后可以确定缓存是否有效并跳过动作方法的调用,直接呈现缓存的内容。

API

表8-1列出了OutputCacheAttribute类的属性。这些设置用来控制OutputCache过滤器如何执行其缓存动作。

表8-1  OutputCacheAttribute类的属性

   

   

CacheProfile

即将使用的缓存设置的名称。它允许将缓

存的配置放到web.config文件中而不是

特性中。随后,该特性可以通过该属性

来引用配置设置

Duration

指定了将输出存储到缓存中的秒数

Location

指定了可能缓存内容的地方。枚举

OutputCacheLocation包含了允许的位置:

Any、Client、Downstream、Server、

None、ServerAndClient等

NoStore

将HTTP题头“Cache-Control: Private,

no-store”设置为阻止浏览器缓存响应。

它等价于调用Response.Cache.SetNoStore


(续表)  

   

   

SqlDependency

特殊格式化的字符串值,包含了一组

输出缓存所依赖的数据库和表的名称

对。当这些表中的数据发生了更改,

则缓存失效

VaryByContentEncoding

在ASP.NET 3.5中引入,这是以逗号

分隔的内容编码的列表,用于变更缓存

VaryByCustom

确定是否基于对Global.asax.cs文件中

的GetVaryByCustomString的调用缓存

新版本的输出。这为开发人员提供了

在缓存时完全的控制

VaryByHeader

基于http题头改变缓存。例如,可能使

用它基于Accept-Language题头缓存

不同版本的输出

VaryByParam

用于指定哪一个QueryString参数导

致了一个新版本的输出被缓存


与@OutputCache指令之间的区别

由于应用程序开发的ASP.NET MVC模型与Web Forms模型之间的区别,所以还有一个选项不会翻译成输出缓存的过滤器,即VaryByControl属性。因此,该属性在OutputCacheAttribute中是没有的。

使用示例

下面将讨论输出缓存过滤器常见的使用模式。在很多情况下,可能希望仅缓存动作的输出一段很短的时间。在下面的代码示例中,缓存了默认的About动作的输出,持续时间为60秒。修改方法的实现以显示时间:


  
  1. [OutputCache(Duration=60, VaryByParam="none")]  
  2. public ActionResult About()   
  3. {  
  4.     ViewData["Title"] = "This was cached at " + DateTime.Now;  
  5.     return View();  

在考虑前面的示例时,我们希望不必每次修改持续时间时就重新编译代码。相反,可能希望在配置文件中设置持续时间。

幸运的是,在web.config中已经存在一个输出缓存的设置部分。下面的样本阐述了如何将缓存设置添加到web.config中:


  
  1. <system.web> 
  2.   <caching> 
  3.     <outputCacheSettings> 
  4.       <outputCacheProfiles> 
  5.         <add name="MyProfile" duration="60" varyByParam="none" /> 
  6.       </outputCacheProfiles> 
  7.     </outputCacheSettings> 
  8.   </caching> 
  9. </system.web> 

注意,添加了一个名为MyProfile的缓存配置文件,现在可以修改输出缓存过滤器来通过CacheProfile属性读取该配置文件的设置:


  
  1. [OutputCache(CacheProfile="MyProfile")]  
  2. public ActionResult About()   
  3. {  
  4.     ViewData["Title"] = "This was cached at " + DateTime.Now;  
  5.     return View();  
  6. }
3  异常过滤器

HandleErrorAttribute是包含在ASP.NET MVC中的默认异常过滤器。如果动作方法抛出一个未处理的异常,且该异常与指定的异常类型匹配或源自它,那么就可以使用该过滤器指定需要处理的异常类型以及需要显示的视图(如果需要的话,还包括主视图)。

默认情况下,如果没有指定异常类型,那么过滤器将处理所有的异常。如果没有指定视图,那么过滤器将默认处理名为Error的视图。默认的ASP.NET MVC项目在Shared文件夹中包含了一个名为Error.aspx的视图。

请看下面的示例:


  
  1. [HandleError(ExceptionType = typeof (ArgumentException), View="ArgError")]  
  2. public ActionResult GetProduct(string name)  
  3. {  
  4.   if(name == null)  
  5.   {  
  6.     throw new ArgumentNullException("name");  
  7.   }  
  8.   return View();  

因为ArgumentNullException继承自ArgumentException,所以将null传递到该动作方法中将导致显示ArgError视图。

在一些情况下,可能希望将多个异常过滤器运用到同一个动作方法中。那么,为了能将最具体的异常类型放在最前面而将较不明确的放在后面,就需要指定这些情况的顺序,这是很重要的。例如,在下面的代码片断中:


  
  1. //This is WRONG!  
  2. [HandleError(Order=1, ExceptionType=typeof(Exception))  
  3. [HandleError(Order=2, ExceptionType=typeof(ArgumentException),   
  4. View="ArgError")]  
  5. public ActionResult GetProduct(string name)  
  6. {  
  7.   …  

第一个过滤器要比其后的过滤器更为通用,它将处理所有的异常,而始终不会给第二个过滤器任何机会来处理异常。为了修复此问题,只需将过滤器从最具体到最不具体进行排序。


  
  1. //This is BETTER!  
  2. [HandleError(Order=1, ExceptionType=typeof(ArgumentException),   
  3. View="ArgError")  
  4. [HandleError(Order=2, ExceptionType=typeof(Exception)]  
  5. public ActionResult GetProduct(string name)  
  6. {  
  7.   …  

当该异常过滤器处理一个异常时,它创建了一个HandleErrorInfo类的实例并设置在呈现Error视图时ViewDataDictionary实例的Model属性。

表8-2展示了HandleErrorInfo类的属性:

表8-2  HandleErrorInfo类的属性

   

   

Action

抛出异常的动作的名称

Controller

在其中抛出异常的控制器的名称

Exception

抛出的异常


注意,该过滤器没有捕捉到在没有启用自定义错误时在调试构建中的异常。过滤器只是检查HttpContext.IsCustomErrorEnabled以确定是否处理该异常。这样做的理由是允许通过信息更丰富的Yellow Screen of Death来显示开发阶段与异常有关的信息。

转自: http://book.51cto.com/art/201006/205387.htm

本文转载自:http://blog.csdn.net/a497785609/article/details/8314152

清山博客
粉丝 3
博文 142
码字总数 30397
作品 0
广州
私信 提问
ASP.NET MVC5请求管道和生命周期

请求处理管道 请求管道是一些用于处理HTTP请求的模块组合,在ASP.NET中,请求管道有两个核心组件:和。所有的HTTP请求都会进入,有进行最终的处理,而通过订阅对象中的事件,可以在对HTTP请求...

雪飞鸿
2017/04/23
0
0
ASP.NET MVC 随笔汇总

ASP.NET MVC 随笔汇总 为了方便大家浏览所以整理一下,有的系列篇幅中不是很全面以后会慢慢的补全的。 学前篇之: ASP.NET MVC学前篇之扩展方法、链式编程 ASP.NET MVC学前篇之Lambda表达式、...

jinyuan0829
2014/08/03
0
0
【更新】Essential Studio for ASP.NET MVC更新至2018 v4(一)

下载Essential Studio for ASP.NET MVC最新版本 Essential Studio for ASP.NET MVC控件包是一款MVC界面开发包,它包含了几乎所有企业级Web应用程序开发所需要的控件,如Grids、 Charts、Gau...

电池盒
2018/12/24
0
0
ASP.NET MVC5 高级编程-学习日记-第一章 入门

1.1 ASP.NET MVC 简介 ASP.NET是一种构建Web应用程序的框架,它将一般的MVC(Model-View-Controller)模式应用于ASP.NET框架。 1.1.1 MVC模式简介 MVC将应用程序的用户界面(User Interface, UI...

可达鸭要进化
2018/12/13
0
0
ASP.NET Web API 2中的错误处理

前几天在webapi项目中遇到一个问题:Controller构造函数中抛出异常时全局过滤器捕获不到,于是网搜一把写下这篇博客作为总结。 HttpResponseException 通常在WebAPI的Controller中抛出的未处...

雪飞鸿
2017/10/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Cloud底层原理

毫无疑问,Spring Cloud 是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术。 不过大多数讲解还停留在对 Spring Cloud 功能使用的层面,其底层的很多原理,很多人可能并不知晓。 ...

月下狼
9分钟前
0
0
Linux重启Tomcat

在测试过程中,要构建测试环境,还经常要重启Tomcat排查问题,重启Tomcat的步骤: 1、首先查看Tomcat是否有启动或重复启动? 输入命令ps -aux|grep java按回车键,可见下图,是有一个Tomcat启...

测试龙管家
9分钟前
0
0
Gartner:阿里云亚太市场份额第一,超过亚马逊和微软总和

4月24日,据彭博社报道,阿里云在亚太云计算市场份额达19.6%,超过亚马逊和微软的总和。这是阿里云连续第二年位居亚太市场第一,份额同比上年增长4.7个百分点,持续扩大领先优势。 报道引述研...

阿里云云栖社区
25分钟前
0
0
Webpack打包优化:使用外链与拆包模式

一、发现问题 这是一个基于 vue-cli 的管理后台项目,由于依赖较多,打包结果如下 二、查找原因 为什么 vendor 体积这么大? 引用的库太多时,vendor的体积会很大,借助 Webpack 的分析工具,...

AI考拉
54分钟前
2
0
ES 集群上,业务单点如何优化升级?

摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! ES 基础 ES 集群 ES 集群上业务优化 一、ES 基础 ES 的安装下载,网上一大片,我这...

泥瓦匠BYSocket
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部