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 voidOnInit(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 overridevoid 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");
         }
}<span style="font-size:14px;">怎么让这个过滤器起作用呢?</span>

步骤:

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 voidRegisterGlobalFilters(GlobalFilterCollection filters)
         {           

                 //filters.Add(newHandleErrorAttribute());
                 filters.Add(newLoginCheckFilterAttribute() { 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,也会造成死循环,解决方案:

执行时出报异常,这时要在Global.asax里添加:开启Session功能

 public class WebApiApplication : System.Web.HttpApplication

    {

        public override void Init()

        {

            this.PostAuthenticateRequest += (sender, e) => HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);

            base.Init();

        }

}

方法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控制器打上了上面的校验特性,
完美解决登录校验的问题。

时间: 2024-07-31 11:19:13

MVC 检测用户是否已经登录的相关文章

[转]MVC 检测用户是否已经登录

本文转自:http://blog.csdn.net/jayzai/article/details/41252137 当我们访问某个网站的时候需要检测用户是否已经登录(通过Session是否为null),我们知道在WebForm中可以定义一个BasePage类让他继承System.Web.UI.Page,重写它的OnInit()方法,在OnInit()中判断Session中是否有用户登录的信息 [csharp] view plaincopyprint? ///<summary> /// 公共基类

MVC下用户登录状态校验的问题以及解决方案--------------Action全局过滤器的使用

前言当我们访问某个网站的时候需要检测用户是否已经登录(通过Session是否为null),我们知道在WebForm中可以定义一个BasePage类让他继承System.Web.UI.Page,重写它的OnInit()方法,在OnInit()中判断Session中是否有用户登录的信息 1 /// <summary> 2 /// 公共基类里面干一些公共的事情 3 /// </summary> 4 public class BasePage : System.Web.UI.Page 5

QQ网站如何检测对本地已经登录的qq用户

网上有很多猜测,比如—— QQ 登录时在本地某地方存登录 ID 信息(Cookie 或文件),用 js 读,然后去服务器认证.但是现在的浏览器一般有沙箱功能,js 无法读到登录 ID:而且在清空 Cookie 后依然起作用. 以 IP.CPU ID.硬盘 ID 等硬件设备 hash 做唯一标识,QQ 登录时在服务器记录此信息,js 验证.感觉这样依赖环境过多,QQ 不太可能采用此方法. QQ 启动某端口监听,js 连接此端口.但是用 netstat 查看后,QQ 并没有监听端口. 有这么一个神奇

七天学会ASP.NET MVC (四)——用户授权认证问题

小编应各位的要求,快马加鞭,马不停蹄的最终:七天学会 Asp.Net MVC 第四篇出炉.在第四天的学习中.我们主要了学习怎样在MVC中怎样实现认证授权等问题.本节主要讲了验证错误时的错误值,client验证,授权认证及登录注销功能的实现. 系列文章 七天学会ASP.NET MVC (一)--深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)--ASP.NET MVC 数据传递 七天学会ASP.NET MVC (三)--ASP.Net MVC 数据处理 七天学会ASP.NET

MVC WebApi 用户验证 (2)

构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(66)-MVC WebApi 用户验证 (2) 前言: 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(65)-MVC WebApi 用户验证 (1) 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访问接口,管理接

Spring MVC +MyBatis +MySQL 简单的登录查询 Demo 解决了mybatis异常

忙活了大半天,饭也没顾得上吃,哎许久不动手,一动手就出事,下面请看今天的重头戏,额吃个饭回来再发了! 1.整体结构 2.准备工作 数据库: --Mysql 5.6 创建数据库 wolf CREATE DATABASE wolf; 创建用户表 user create table user( id int  AUTO_INCREMENT  primary key, name varchar(25) not null, pwd varchar(20) not null, create_time dat

ASP.NET MVC5+EF6+EasyUI 后台管理系统(65)-MVC WebApi 用户验证 (1)

系列目录 前言: WebAPI主要开放数据给手机APP,其他需要得知数据的系统,或者软件应用,所以移动端与系统的数据源往往是相通的. Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问 本文通过Basic 方式进行基础认证Mvc的Controller基类及Action的权限验证来实现Web系统登录,Mvc前端权限校验以及WebApi服务端的访问校验功能,本文主要作为本人备忘使用,如能给予人帮助,深感荣幸,欢迎讨论和指正,下面梳

构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(66)-MVC WebApi 用户验证 (2)

前言: 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(65)-MVC WebApi 用户验证 (1) 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访问接口,管理接口,利用系统权限管理接口,对每个接口进行授权(管理接口为选读部分,因为你需要阅读最开始权限管理部分(18-27节),才能阅读这部分) 开发环境: V

MVC应用程序实现会员登录功能

实现之前,我们已经把验证成功的信息存在cookie里<MVC登录前准备写好cookie>http://www.cnblogs.com/insus/p/3464105.html.现在就可以实现真正的验证与登录了. 先去数据库,写好一个登录证的存储过程[dbo].[usp_Member_LoginVerifyAndGetInfo]: 存储过程中有两个判断,用户输入一个不存在的帐号,也要提示帐号或是密码错误,为了系统安全考虑,一般不建议分别提示. 去应用程序,找到Entities目录,修改Membe