所有的web系統,只要是有用戶登錄這一塊有權限這個的需求的就要處理用戶登錄狀態保存這個問題,如果沒有登錄,那麼跳轉到登錄頁面讓用戶登錄。
在webform中,一般是通過讓頁面繼承System.Web.UI.Page,重寫它的OnInit()方法,在OnInit()中判斷Session中是否有用戶登錄的信息;頁面也有PageLoad()方法,但是在頁面的生命週期中,Init方法先執行,所以,截獲OnInit,重寫父類的init方法最準確;
public class BasePage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Session["UserInfo"] == null) //如果用戶沒有登錄
{
//跳轉到登錄頁面
}
}
}
在MVC中,MVC下可以自定義特性類爲控制器或控制器中的Action打上[特性],這裏只需要ActionFilter過濾器(Action方法執行前後執行),微軟已提供好的ActionFilterAttribute類,他是篩選器特性的基類,也是一個抽象類,其實這個抽象類實現了IActionFilter和IResultFilter,
IActionFilter接口的定義了兩個方法:
//在執行操作方法後調用。
void OnActionExecuted(ActionExecutedContext filterContext);
// 在執行操作方法之前調用。
void OnActionExecuting(ActionExecutingContext filterContext);
我們如果也要做驗證控制,那麼我們首先新建一個自己需求的特性類,讓他繼承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["UserInfo "] == null)
{
//跳轉到登陸頁
filterContext.HttpContext.Response.Redirect("/admin/login");
}
}
}
}
然後在全局中註冊這個過濾器。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new LoginCheckFilterAttribute() { IsCheck = true });
}
}
這樣,你就可以在你的controller類中去使用這個filter特性。如果你在你的action前加上了這個過濾器,那麼在執行這個Action方法之前會先調用特性類中的重寫OnActionExecuting方法,這樣用戶在訪問網站的時候會首先檢測用戶是否已經登錄,如果沒有登錄會跳轉到登錄頁面。
但是這樣做,你會很費勁,你每個action都要弄一遍。
對於客戶端的發來的請求,響應都由路由交給了controller控制器,同webform方式一樣,也可以採取同樣的方式,讓我們的controller類繼承自System.Web.Mvc.Controller;
System.Web.Mvc.Controller這個類實現了IActionFilter這個接口,那麼我們就可以自己來覆蓋OnActionExecuting方法,在這個我們自己定義的controller基類中做好這些登錄驗證;
形如代碼:protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var reurl = filterContext.HttpContext.Request.Url == null
? "#"
: filterContext.HttpContext.Request.Url.PathAndQuery;
if (!filterContext.HttpContext.Request.IsAuthenticated)
{
// filterContext.Result = RedirectToAction("index", "login", new { ReturnUrl = reurl });
}
else
{
if (null != Session["UserInfo "])
{
ViewBag.UserName = Session["UserInfo "].Name;
ViewBag.CurrentUser = Session["UserInfo "];
if (filterContext.HttpContext.Request.UrlReferrer != null)
{
ViewBag.Reurl = filterContext.HttpContext.Request.UrlReferrer.PathAndQuery;
}
}
else
{
filterContext.Result = RedirectToAction("index", "login", new { ReturnUrl = reurl });
return;
}
}
}
這裏要注意的是,這裏不能使用
Response.Redirect("/Login/index");
這種方式來調整到登錄頁面。這會導致:
“無法在發送 HTTP 標頭之後進行重定向。”這種錯誤;
請使用:
filterContext.Result = RedirectToAction("index","login", new { ReturnUrl = reurl });
還有可能會碰到這個問題就是瀏覽器報錯誤:
“此網頁包含重定向循環”
這是由於你的疏忽造成的,你想想,當你沒有登錄時,檢測到session沒有,爲空,所以定向到了登錄,登錄的action被捕獲,本應該到登錄頁面,但是OnActionExecuting要先執行,於是進入死循環了。這個死循環的解脫也簡單,因爲登錄頁面根本就不需要驗證登錄,所以我們可以建立個新的controller基類,裏面不去覆蓋OnActionExecuting方法,不做登錄驗證跳轉這個步驟,這樣的話就可以逃出這個死循環;這也是符合設計需求的;