过滤器本质就是对动做方法的执行过程进行干预,这种干预能够影响动做方法执行的各个过程。ASP.NET MVC 提供了4种类型的接口,并在接口中定义了各类成员,表明代码执行的各个阶段,这些接口和成员如表11-1所示。 html
表11-1 常见过滤器接口 web
过滤器类型数据库 |
接口app |
默认实现ide |
描述函数 |
Action加密 |
IActionFilterspa |
ActionFilterAttribute设计 |
在动做方法以前及以后运行日志 |
Result |
IResultFilter |
ActionFilterAttribute |
在动做结果被执行以前和以后运行 |
AuthorizationFilter |
IAuthorizationFilter |
AuthorizeAttribute |
首先运行,在任何其它过滤器或动做方法以前 |
Execption |
IExceptionFilter |
HandleErrorAttribute |
只在另外一个过滤器、动做方法、动做结果弹出异常时运行 |
当动做方法同时应用了继承自这些特性的过滤器后,实际的执行过程如图11-1所示。
图11-1 过滤器执行过程
图11-1中流程并无列出 OnException() 方法的执行时机,事实上,在执行流程中只要任何环节出现异常,就会执行 OnException()方法。
ASP.NET MVC 的这种过滤器机制,实际是体现了一种 AOP(面向切面) 设计思想,当须要为动做方法进行干预时,不须要变更动做方法内部的代码,就能够扩张横向的行为。在实际开发中,只须要继承这些接口,实现自定义的特性,并在动做方法上应用自定义的特性,就能够扩展动做方法的能力。实现自定义的过滤器特性,须要知足两个要求。一是实现表11-1中任意的接口,二是继承FilterAttribute,标识它是一个过滤器。接下来介绍自定义过滤器的用法。
在ASP.NET MVC 项目中建立文件夹Filter,而后新建类MyActionFilterAttribute(为了遵循默认的约定,名称以Attribute结尾),继承自ActionFilterAttribute类。ActionFilterAttribute类有以下4个方法。
public virtual void OnActionExecuted(ActionExecutedContext filterContext);
public virtual void OnActionExecuting(ActionExecutingContext filterContext);
public virtual void OnResultExecuted(ResultExecutedContext filterContext);
public virtual void OnResultExecuting(ResultExecutingContext filterContext);
MyActionFilterAttribute.cs 类的代码如示例1所示。
示例1
public class MyActionFilterAttribute : ActionFilterAttribute { //Action执行以前 public override void OnActionExecuting(ActionExecutingContext filterContext) { //一、获取请求的类名和方法名 string strController = filterContext.RouteData.Values["controller"].ToString(); string strAction = filterContext.RouteData.Values["action"].ToString();
//二、用另外一种方式获取请求的类名和方法名 string strController2 = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string strAction2 = filterContext.ActionDescriptor.ActionName;
filterContext.HttpContext.Response.Write("控制器:" + strController + "<br/>"); filterContext.HttpContext.Response.Write("控制器:" + strController2 + "<br/>"); filterContext.HttpContext.Response.Write("Action:" + strAction + "<br/>"); filterContext.HttpContext.Response.Write("Action:" + strAction2 + "<br/>"); filterContext.HttpContext.Response.Write("Action执行前:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>"); base.OnActionExecuting(filterContext);
} //Action执行以后 public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("Action执行后:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>"); base.OnActionExecuted(filterContext); } } |
对于过滤器,咱们能够把它们加在3个地方,一个是控制器上面(控制器下面的全部Action),一个是Action上面(指定标识的Action),另外一个就是全局位置(全部控制器中的Action)
在控制器上代码以下:
[MyActionFilter]
public ActionResult Index()
{
return View();
}
在Filter文件夹中新建MyResultFilterAttribute类,继承ActionFilterAttribute。如示例2所示。
示例2
public class MyResultAttribute: ActionFilterAttribute { // 加载"视图"前执行 public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.HttpContext.Response.Write("加载视图前执行 OnResultExecuting" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>"); base.OnResultExecuting(filterContext); } // 加载"视图"后执行 public override void OnResultExecuted(ResultExecutedContext filterContext) { filterContext.HttpContext.Response.Write("加载视图后执行 OnResultExecuted" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>"); base.OnResultExecuted(filterContext); } } |
这里把MyResultFilter过滤器加在控制器上面,至关于给Home控制器中的全部的Action方法添加了MyResultFilter过滤器。以下代码所示。
[MyResultFilter] public class HomeController : Controller { [MyActionFilter] public ActionResult Index() { return View(); } } |
建立MyAuthorizeAttribute类,继承AuthorizeAttribute类。如示例3所示。
示例3
public class MyAuthorizeAttribute: AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { filterContext.HttpContext.Response.Write("OnAuthorization<br/>"); //注释掉父类方法, //由于父类里的OnAuthorization方法会调用ASP.NET的受权验证机制 //base.OnAuthorization(filterContext); } } |
在控制器Home中的Index上添加MyAuthorize过滤器。
[MyActionFilter] [MyAuthorize] public ActionResult Index() { return View(); } |
一般Authorize过滤器也是在全局过滤器上面的,主要用来作登陆验证或者权限验证,在App_Start目录下的FilterConfig类的RegisterGlobalFilters方法中添加:
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); //添加全局受权过滤器 filters.Add(new MyAuthorizeAttribute()); } } |
在全局中注册过滤器,则全部控制器的全部行为(Action)都会执行这个过滤器。
建立MyHandleErrorAttribute类,继承HandleErrorAttribute类。如示例4所示。
示例4
public class MyHandleErrorAttribute: HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { //一、获取异常对象 Exception ex = filterContext.Exception; //二、记录异常日志 (将错误信息利用IO保存到文件)
//三、重定向友好页面 filterContext.Result = new RedirectResult("~/error.html"); //四、标记异常已经处理完毕 filterContext.ExceptionHandled = true;
base.OnException(filterContext); } } |
在Action上面添加MyHandleError过滤器,以下所示。
[MyHandleError] public ActionResult GetErr() { int a = 0; int b = 1 / a; return View(); } |
运行会自动跳转到error.html页面。
若是页面没有跳转,就须要去Web.config配置文件中的<system.web>节点下面添加以下配置节点,开启自定义错误:
<customErrors mode="On"></customErrors>
一般这样的异常处理是放在全局过滤器上面的,只要任意Action方法报错就会执行MyHandleError过滤器中的代码。
修改App_Start目录下面的FilterConfig类:
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //添加全局受权过滤器 filters.Add(new MyAuthorizeAttribute()); //添加全局异常处理过滤器 filters.Add(new MyHandleErrorAttribute()); } } |
Global.asax下的代码:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { App_Start.AutoMapperConfig.Config();
AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } } |
身份验证流程
1、用户登陆
一、验证表单:ModelState.IsValid
二、验证用户名和密码:经过查询数据库验证
三、若是用户名和密码正确,则在客户端保存Cookie以保存用户登陆状态:SetAuthCookie
1):从数据库中查出用户名和一些必要的信息,并把额外信息保存到UserData中
2):把用户名和UserData保存到 FormsAuthenticationTicket 票据中
3):对票据进行加密 Encrypt
4):将加密后的票据保存到Cookie发送到客户端
四、跳转到登陆前的页面
2、验证登陆
一、在Global中注册PostAuthenticateRequest事件函数,用于解析客户端发过来的Cookie数据
1):经过 HttpContext.Current.User.Identity 判断用户是否登陆(FormsIdentity,IsAuthenticated,AuthenticationType)
2):从HttpContext 的Request的Cookie中解析出Value,解密获得 FormsAuthenticationTicket 获得UserData
二、角色验证
在Action加入 Authorize特性,能够进行角色验证
在 HttpContext.Current.User 的 IsInRole 方法进行角色认证(须要重写)