前言當我們訪問某個網站的時候需要檢測用戶是否已經登錄(通過Session是否為null),我們知道在WebForm中可以定義一個BasePage類讓他繼承System.Web.UI.Page,重寫它的OnInit()方法,在OnInit()中判斷Session中是否有用戶登錄的信息。 在mvc下該怎 ...
前言當我們訪問某個網站的時候需要檢測用戶是否已經登錄(通過Session是否為null),我們知道在WebForm中可以定義一個BasePage類讓他繼承System.Web.UI.Page,重寫它的OnInit()方法,在OnInit()中判斷Session中是否有用戶登錄的信息。
/// <summary> /// 公共基類裡面乾一些公共的事情 /// </summary> public class BasePage : System.Web.UI.Page { //頁面生命周期Init事件對應的OnInit()方法 //這個方法會先於PageLoad方法執行 //override 表示重寫 OnInit方法 OnInit 方法,在所有控制項都已初始化且已應用所有外觀設置後引發。使用該事件來讀取或初始化控制項屬性 protected override void OnInit(EventArgs e) { base.OnInit(e); if (Session["UserInfo"] == null) //檢查用戶是否登錄 { //跳轉到登錄頁面 } } }
在mvc下該怎樣校驗呢?
我們知道,MVC下可以自定義特性類為控制器或控制器中的Action打上[特性],這裡只需要ActionFilter過濾器(Action方法執行前後執行),MVC提供了IActionFilter介面。(為了方便我們可以用微軟提供好的ActionFilterAttribute類,他是篩選器特性的基類,也是一個抽象類,其實這個抽象類實現了IActionFilter和IResultFilter)
IActionFilter介面的定義:
//在執行操作方法後調用。 void OnActionExecuted(ActionExecutedContext filterContext); // 在執行操作方法之前調用。 void OnActionExecuting(ActionExecutingContext filterContext);
新建一個特性類LoginCheckFilterAttribute,讓他繼承ActionFilterAttribute,並重寫其中的OnActionExecuting方法,在其中完成校驗
public class LoginCheckFilterAttribute : ActionFilterAttribute { //表示是否檢查登錄 public bool IsCheck { get; set; } //Action方法執行之前執行此方法 public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); if (IsCheck) { //校驗用戶是否已經登錄 if (filterContext.HttpContext.Session["loginUser"] == null) { //跳轉到登陸頁 filterContext.HttpContext.Response.Redirect("/UserLogin/Index"); } } } }
怎麼讓這個過濾器起作用呢?
步驟:1、在Global.asax文件中為MVC程式註冊全局過濾器, 調用FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters)。FilterConfig類在App_Start文件夾中(創建新的MVC項目會自動生成),在FilterConfig的靜態方法中public static void RegisterGlobalFilters(GlobalFilterCollection filters)註冊全局過濾器
public class FilterConfig { //這個方法是用於註冊全局過濾器(在Global中被調用) public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); filters.Add(new LoginCheckFilterAttribute() { IsCheck = true }); } }
註意要為特性類實例的IsCheck屬性賦值true否則Session校驗不起作用。
這樣子,LoginCheckFilterAttribute這個特性就會對整個MVC程式中的控制器和Action起作用了,就是說在執行Action方法之前會先調用特性類中的重寫OnActionExecuting方法,這樣用戶在訪問網站的時候會首先檢測用戶是否已經登錄,如果沒有登錄會跳轉到登錄頁面。
但是!但是!問題來了,因為我們註冊的是全局的過濾器,這個過濾特性會對所有的控制器下的Action起作用,當訪問網站的時候會(比如我們註冊預設路由為/Home/Index)會首先跳轉到/Home/Index,這時不會執行Index方法,會先執行OnActionExecuting()中的校驗,發現Session為null,Response.Redirect("/UserLogin/Index")跳轉到了登錄頁面;這時我們在瀏覽器中依然看不到登錄頁面,為什麼呢?還記得我們註冊的全局的過濾器,作用對象包括所有控制器下的Action當然也包括/UserLogin/Index,代碼走到了這裡會再次執行OnActionExecuting()方法,發現Session["UserInfo"==]null,又跳到了登錄頁面,我們連登錄頁面都見不著肯定不能輸入用戶名密碼Session也就不會有登錄信息,瀏覽器會返回 ”此網頁包含重定向迴圈“ 的錯誤頁面,也就是說會一直迴圈不停的重定向到登錄頁面,類似死迴圈,瀏覽器當然罷工了。。
該怎樣解決這個bug的?
解決方法:為UserLoginController控制器打上特性
[LoginCheckFilterAttribute(IsCheck = false)] //打上用戶登錄校驗特性(IsCheck設為false不讓它對此控制器起作用,而對其他控制器和Action起作用,防止重定向迴圈) public class UserLoginController : Controller { ... }
我們在定義這個特性類的時候 有個bool屬性 IsCheck,它表示是否校驗,這裡設為false表示不校驗。順便說一下LoginCheckFilterAttribute可以省略Attrbute尾碼。
一定要在控制器上打這個特性,不要只針對下邊的某個Action,因為這裡邊有生成驗證碼的Action和處理登錄請求的Action,它們都不需要進行session校驗(沒意義),在控制器上打上特性會對它下邊的所有Action起作用,不用為每個Action打特性了,節省代碼量。我們註冊了全局過濾器,又單獨為UserLoginController控制器打上過濾特性,這裡有一個優先順序的問題Action>Controller>全局,UserLoginController不會受全局過濾器的影響。到這裡測試一下,輸入網站地址,成功進入登錄頁面。問題解決。
本文主要參考了:http://www.cnblogs.com/Look_Sun/p/4425083.html這篇文章。我遇到這個問題的時候,看了這篇文章和我開發時候遇到的問題基本一樣。但是那哥們寫的全局過濾器好像有問題,只需要判斷Session["userinfo"]==null的時候就可以,他把Session["userinfo"]!=null的時候也做了判斷,並做了跳轉到。所有當點擊登陸的時候,重定向到了/Home/Index,但是到了Home又會是個死迴圈。
MVC中過濾器中非常好的一個視屏:http://pan.baidu.com/s/1i5zwhjZ 回覆我要密碼 以後共同探討問題