過濾器本質就是對動做方法的執行過程進行干預,這種干預能夠影響動做方法執行的各個過程。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 方法進行角色認證(須要重寫)