.Net Core MVC重寫OnActionExecuting方法實現過濾器功能
需求
登錄校驗
實現方式
通過重寫OnActionExecuting
方法,實現過濾器
原理
我們知道每個Controller/Action
請求都會觸發OnActionExecuting
方法,那麼我們重寫此方法,並判斷當前User是否登錄(筆者通過Cookie方式驗證,見上一篇博客)如果登錄信息存在Cookie那麼讓他可以訪問頁面,如果沒登錄或者登錄過期,重定向到登錄頁
具體實現Code
1.定義一個BaseController
public class BaseController : Controller
{
//複寫父類的該方法。執行控制器中的方法之前先執行該方法。從而實現過濾的功能。
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//string _controllerName = filterContext.RouteData.Values["controller"].ToString();
//string _actionName = filterContext.RouteData.Values["action"].ToString();
//object _routeName = filterContext.RouteData.DataTokens["area"];
base.OnActionExecuting(filterContext); //調用父類的該方法。
if (Request.Cookies["CurrentUser"] != null)
{
//filterContext.HttpContext.Response.Redirect("/QRCodeRecruitment/Index"); //這種跳轉方式,會繼續向下執行Controller的方法並返回ActionResult。
}
else
{
//這種跳轉方式直接返回一個ActionResult,不會繼續向下執行,而是直接跳轉。速度快。
filterContext.Result = Redirect("/Login/index"); ///ManageUATClient
}
}
}
2.繼承BaseController
public class QRCodeRecruitmentController : BaseController
{
public IActionResult Index()
{
RecruitModel model = new RecruitModel();
///具體請求代碼...
return View(model);
}
}
這樣當直接訪問/QRCodeRecruitment/Index
會被OnActionExecuting
攔截,通過Debug可以看見斷點會先進入OnActionExecuting
,至於方法裏的判斷Request.Cookies["CurrentUser"] != null
則是在用戶通過登錄加入到Cookie裏的了,如果沒登陸過直接跳登錄頁filterContext.Result = Redirect("/Login/index");
PS:筆者研究了一晚上,研究出來的一種適用於.Net Core的攔截器方式,至於.Net Core自身帶的那種登錄驗證筆者也試過了。就是用起來比較繁瑣,得先熟悉他本身的那套套路,最不能接受是EF,由於常年維護帶EF的項目,每次改表結構都非常難受,因此筆者不建議EF的,況且EF使用了大量的反射機制,會使查詢速度變慢。當然創建時候是很爽,維護起來可糟心了。
就寫這麼多了,覺得有用點贊評論,大家一起交流
針對ajax/bootstrapTable異步請求不跳頁的補充
補充背景
本以爲就這樣結束了,問題很快暴露出來,那就是Ajax請求訪問數據時,Cookie到期情況,跳頁不成功,Ajax本身就是不刷新頁面的嘛,到攔截器裏面即使filterContext.Result = Redirect("/Login/index");
放這個招也不好用,URL是不會變的。那也就意味着,用戶登錄過期以後,點擊什麼也請求不到,還沒反應,我們希望的是重定向到登錄頁。
解決思路
我們在攔截器(過濾器)裏判斷當前請求到底是URL還是異步請求,當時用戶輸入地址的URL請求時,正常走原來的邏輯跳頁,當是Ajax異步請求時,給返回狀態碼,到Ajax請求的返回結果去重定向,問題可解。
具體Code實現
public class BaseController : Controller
{
public static string childSite = "";
//複寫父類的該方法。執行控制器中的方法之前先執行該方法。從而實現過濾的功能。
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (ConfigurationManager.AppSettings["environment"] == "Prod")
{
childSite = "/ManageUATClient";
}
base.OnActionExecuting(filterContext); //調用父類的該方法。
if (Request.Cookies["CurrentUser"] != null)
{
}
else
{
//是否爲Ajax請求,Ajax需要返回碼,Ajax請求不能直接跳轉
if (filterContext.HttpContext.Request.Headers.ContainsKey("x-requested-with"))
{
if(filterContext.HttpContext.Request.Headers["x-requested-with"] == "XMLHttpRequest")
{
filterContext.Result = new ContentResult() { Content = "CookieTimeOut", StatusCode = 499 };
}
}
else
{
filterContext.Result = Redirect(childSite + "/Login/index");
}
}
}
}
前臺Ajax處理代碼
$.ajax({
url: ...
type: "POST",
dataType: "json",
data: { ... },
success: function (result) {
///..
},
error: function (e) {
if (e.status = 499) {
window.location.href = "/Login/Index";
}
console.log(e.status);
console.log(e.responseText);
}
});
bootstrapTable處理代碼
onLoadError: function (status, jqXHR) {
if (status = 499) {
window.location.href = "/Login/Index";
}
console.log(status);
console.log(jqXHR.responseText);
},
這樣即使登錄過期了,用戶點了什麼東西請求數據就會跳到登錄頁。
**
針對ActionFilterAttribute實現單個或者整個Controller攔截器(過濾器)的補充(2020/06/11 v3.0)
**
上述BaseController : Controller
這種寫法是整個繼承了BaseController
的所有Action
都被攔截,那麼如果希望只攔截某個Action
的時候怎麼實現呢?本次補充單個Action
的攔截實現。
依然是重寫OnActionExecuting
方法
public class WxOauthAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//code etc...
}
}
注意這裏的WxOauthAttribute
類,這個類名前綴WxOauth
關鍵字放在Action
頭上[WxOauth]
即可起到單個Action
攔截的作用,即
[WxOauth]
public ActionResult Index(string str)
{
return View();
}
放在Controller
頭上會不會攔截所有Action
呢?感興趣可以試試
[WxOauth]
public class ClientController : Controller
{
//...
}
此寫法只在.NET Framework MVC嘗試過,.NET Core沒試過暫時先補充進來
PS:後期再有優化還發在這裏,持續關注哦
僅供學習參考,如有侵權聯繫我刪除