.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:后期再有优化还发在这里,持续关注哦
仅供学习参考,如有侵权联系我删除