zoukankan      html  css  js  c++  java
  • 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");
                    }
                    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)注册全局过滤器

    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控制器打上特性   

        [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这个类发现

    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

  • 相关阅读:
    target runtime apache v6.0 not defined解决
    java.lang.AbstractMethodError: javax.servlet.jsp.JspFactory.getJspApplicationContext(Ljavax/servlet/ServletContext;)Ljavax/servlet/jsp/JspApplicationContext;
    The valid characters are defined in RFC 7230 and RFC 3986问题
    invalid END header解决方法
    You have more than one version of ‘org.apache.commons.logging.Log’ visible, which is not allowed问题解决
    Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    在eclipse中import java web项目时遇到的一些问题并将该项目通过tomcat发布
    java byte转string 涉及到字节流中有中文
    spring+mybatis框架搭建时遇到Mapped Statements collection does not contain value for...的错误
    试试看读一下Zepto源码
  • 原文地址:https://www.cnblogs.com/xsj1989/p/5584046.html
Copyright © 2011-2022 走看看