前言当我们访问某个网站的时候需要检测用户是否已经登录(通过Session是否为null),我们知道在WebForm中可以定义一个BasePage类让他继承System.Web.UI.Page,重写它的OnInit()方法,在OnInit()中判断Session中是否有用户登录的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /// <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接口的定义:
1 2 3 4 | //在执行操作方法后调用。 void OnActionExecuted(ActionExecutedContext filterContext); // 在执行操作方法之前调用。 void OnActionExecuting(ActionExecutingContext filterContext); |
新建一个特性类LoginCheckFilterAttribute,让他继承ActionFilterAttribute,并重写其中的OnActionExecuting方法,在其中完成校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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" ); } else { //跳转到首页 filterContext.HttpContext.Response.Redirect( "/Home/Index" ); } } } } |
怎么让这个过滤器起作用呢?
步骤:
1、在Global.asax文件中为MVC程序注册全局过滤器, 调用FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters)。FilterConfig类在App_Start文件夹中(创建新的MVC项目会自动生成),在FilterConfig的静态方法中public static void RegisterGlobalFilters(GlobalFilterCollection filters)注册全局过滤器
1 2 3 4 5 6 7 8 9 | 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的?
我尝试了两种解决办法:
方法1:为UserLoginController控制器打上特性
1 2 3 4 | [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不会受全局过滤器的影响。
到这里测试一下,输入网站地址,成功进入登录页面,输入正确的用户名密码点击登录,浏览器又返回了“此网页包含重定向循环”
的错误信息,调试了一下还是之前那个问题,只不过能显示了登录页面,登录后Session["UserInfo"]有了用户,依然会无限重定向,因为会在OnActionExecuting()在Action之前执行,这时即使Sessio["UserInfo"]!=null,也会造成死循环,方法1失败
方法2:利用BaseController类(类似WebFrom的BasePage)
1、新建一个BaseController类,继承System.Web.Mvc.Controller,类中定义一个UserInfo属性,保存从Session["UserInfo"]中拿出的用户实体,方便他的派生类调用。
2、F12定义一下System.Web.Mvc.Controller这个类发现
1 2 3 4 | public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IController, IAsyncManagerContainer { //... } |
它竟然也实现了IActionFilter接口,那就用不着上面我们的全局过滤器了,只需要重写OnActionExecuting()方法,逻辑和过滤器中的代码一样,让需要进行登录校验的控制器来继承BaseController类就可以了,相当于为BaseController控制器打上了上面的校验特性, 完美解决登录校验的问题。
转自:http://www.cnblogs.com/Look_Sun/p/4425083.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】