网页过期弹出功能

该功能的引入目的很简单,防止人员离开工位时忘记登出系统,其他人员冒名操作,追责时产生争议。

首先,介绍下本文的参考资料:

  0. Http请求处理流程  

IIS 、Framework、Asp.Net 是如何协同工作处理每个Http请求、如何区分不同的请求、IIS、Framework、Asp.Net三者之间的数据如何流动?

能够处理各种后缀名的应用程序,通常被称为 ISAPI 应用程序(Internet Server Application Programe Interface,互联网服务器应用程序接口)
Asp.Net 只是服务器(IIS)的一个组成部分而已,它是一个 ISAPI扩展。

HttpRuntime类是Asp.Net的一个主要入口,它有一个称作 ProcessRequest 的方法,这个方法以一个 HttpWorkerRequest 类作为参数。HttpRuntime 类几乎包含着关于单个 Http请求的所有信息:
所请求的文件、服务器端变量、QueryString、Http 头信息 等等。
当 Web.config文件的内容发生改变 或者 .aspx文件发生变动的时候,为了能够卸载运行在同一个进程中的应用程序(卸载也是为了重新加载),Http请求被分放在相互隔离的应用程序域中。
对于IIS来说,它依赖一个叫做 HTTP.SYS 的内置驱动程序来监听来自外部的 HTTP请求。在操作系统启动的时候,IIS首先在HTTP.SYS中注册自己的虚拟路径。

当Http请求进入 Asp.Net Runtime以后,它的管道由托管模块(NOTE:Managed Modules)和处理程序(NOTE:Handlers)组成,并且由管道来处理这个 Http请求。

 

 

 

  1. HttpModule介绍

一般来说,我们可以将Asp.Net中的事件分成三个级别,最顶层是 应用程序级事件、其次是页面级事件、最下面是控件级事件,事件的触发分别与 应用程序周期、页面周期、控件周期紧密相关。
而 Http Module 的作用是与应用程序事件 密切相关的。

 Asp.Net 内置的 Http Modules

 

  整个过程如下:

  1. 当站点第一个资源被访问的时候,Asp.Net会创建HttpApplication类的实例,它代表着站点应用程序,同时会创建所有在Web.Config中注册过的Module实例。

  2. 在创建Module实例的时候会调用Module的Init()方法。

  3. 在Init()方法内,对想要作出响应的HttpApplication暴露出的事件进行注册。(仅仅进行方法的简单注册,实际的方法需要另写)。

  4. HttpApplication在其应用程序周期中触发各类事件。

  5. 触发事件的时候调用Module在其Init()方法中注册过的方法。

  2. HttpModule模块作用之三通过Session判断用户是否登陆

  3. 判断Session过期

上述两个参考文档是可以直接参考的代码,非原理性讲解。

  4. 利用HttpModule开发asp.net页面、ashx等访问时session失效的统一处理入口

HttpApplication处理事件的先后顺序,不同事件会处理不同的事情,需要注意使用顺序。

  5. ASP.NET三剑客 HttpApplication HttpModule HttpHandler 解析

详细介绍了上述博客提到的HttpApplication、HttpModule、HttpHandler等对象

  6. ASP.NET Session 简单超实用使用总结

  7. ASP.NET 中的 Session 怎么正确使用

  8. ASP.NET的session操作方法总结

上面介绍的方法都是通过HttpModule判断session是否失效来决定是否返回登陆页面。
那么什么是Session,怎么设定Session的存续事件,集群环境下Session如何处理?这些问题的答案可以参考6-8这3篇博客。

 

经过上面的参考文档,我们的代码如下:

public class ModuleBackLogin : IHttpModule
{
    public ModuleBackLogin()
    {
        //
        // TODO: 在此处添加构造函数逻辑
        //
    }

    // Init方法仅用于给期望的事件注册方法
    public void Init(HttpApplication context)
    {
        context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
    }

    // 处理context_PreRequestHandlerExecute事件的实际代码
    void context_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        try
        {
            HttpApplication ha = (HttpApplication)sender;//获得发生该事件的对象
            string path = ha.Context.Request.Url.ToString();//获得请求的url路径
            int n = path.IndexOf("Login.aspx"); //判断是否是登陆页面
            int m = path.IndexOf("LoginHandler.ashx");

            //不是登录页面,也不是登录操作
            if (n < 0 && m < 0)
            {
                if (ha.Context.Session != null)
                {
                    if (ha.Context.Session[KeyConst.UserId] == null)
                    {
                        ha.Response.Write("<script>alert('登陆超时或者非法登录,请重新登录!!');top.window.location.href='Login.aspx';</script>");
                        ha.Response.End();
                    }
                }
            }
        }
        catch { }
    }

    public void Dispose()
    {
    }
}
HttpModule
<?xml version="1.0" encoding="utf-8"?>

<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->

<configuration>

    <system.web>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" requestValidationMode="2.0"/>
      <!--<httpModules>
        <add name="MyModule" type="ModuleBackLogin" />
      </httpModules>-->
      <sessionState  mode="InProc"  timeout="10"/>
      <!--<httpRuntime requestValidationMode="2.0" />-->
      <pages validateRequest="false"></pages>
    </system.web>

  <system.webServer>
    <modules>
      <add name="MyModule" type="ModuleBackLogin" />
    </modules>
  </system.webServer>
  
</configuration>
Web.Config

 

 

上述的参考文档及代码是使用ASP.NET及Session判断网页过期及强制重新登录。

下一个项目我们使用的是ASP.NET MVC,那么这个要怎么处理呢?上述解决方案还有一个隐藏问题,如果请求页面是OK的,但是如果是AJAX请求,那么页面会报错,但是并不会强制重新登录,这个问题要怎么解决呢?请继续往下阅读~

 

参考资料如下:

  1. Asp.net MVC使用Filter解除Session, Cookie等依赖

filter的简单介绍。
MVC对HTTP请求的处理和ASP.NET有些不一样,比如MVC是通过给Controller加Filter,ASP.NET是通过HttpModule。

  2. Asp.net MVC Session过期异常的处理

该文章介绍了使用Filter进行session过期的判断。
也解决了前文我提到的一个问题,AJAX请求失败的问题。
但是文章还有个问题待解决,难道要在网页上所有的ajax请求处都要加以处理?

  3. 授权过期后AJAX操作跳转到登录页的一种全局处理方式

当授权过期后,针对ajax请求返回一个特定的标识,然后前端通过识别该标识,来跳转到登录页面。而且最好不用在每处ajax请求的代码中都加上对这种标识判断,即要能全局处理。
所以目标就落在了jQuery.ajax的全局配置($.ajaxSetup)上了,通过查看API,发现statusCode参数用来做这件事再好不过了,而且重要的是,即使ajax代码中禁用了全局配置(global:false),
关于statusCode的配置都仍然有效(这点对我们之前项目中来说很重要,因为有很多的ajax都禁用了全局的遮罩效果)。

  4. MVC过滤器处理Session过期

如果不想在每个controller上都加特性,那么可以将filter注册成全局过滤器。

综上,MVC中我们的代码如下:

namespace MySpace
{
    /// <summary>
    /// 判断是否登录的过滤器
    /// </summary>
    public class JudgmentLoginAttribute : ActionFilterAttribute
    {
        //执行Action之前操作
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {

            //判断是否登录或是否用权限,如果有那么就进行相应的操作,否则跳转到登录页或者授权页面
            string s_accountId = HttpUtility.UrlDecode(CookiesHelper.GetCookieValue("UserID")); 
            string s_loginTime = HttpUtility.UrlDecode(CookiesHelper.GetCookieValue("LoginTime")) == ""?"2000-01-01 00:00:00": HttpUtility.UrlDecode(CookiesHelper.GetCookieValue("LoginTime"));
            if((DateTime.Now -DateTime.Parse(s_loginTime)).Minutes >30)//超时30分钟则需要重新登录
            {
                if (filterContext.HttpContext.Request.IsAjaxRequest())
                {
                    filterContext.Result = new HttpStatusCodeResult(499);
                    filterContext.HttpContext.Response.Write("alert('登陆超时或者非法登录,请重新登录!');top.window.location.href='/Auth/Login';");
                }
                else
                {
                    HttpContext.Current.Response.Write("<script>alert('登陆超时或者非法登录,请重新登录!');top.window.location.href='/Auth/Login';</script>");

                }
            }
            else
            {
                CookiesHelper.SetCookie("LoginTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            }
        }
    }
}
JudgmentLoginAttribute
[MySpace.JudgmentLogin]
public class HomeController : Controller
特性
$.ajaxSetup({
            statusCode: {
                499: function (data) {
                    //console.log(data);
                    eval(data.responseText);
                }

            }
        });
页面加上JS

 

posted @ 2019-08-06 12:49  XIAOQINQIN  阅读(262)  评论(0编辑  收藏  举报