zoukankan      html  css  js  c++  java
  • 网页过期弹出功能

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

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

      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
  • 相关阅读:
    kafka-python基本使用
    RabbitMq 消息队列详解
    Socket 编程
    python 进程, 线程 ,协程,锁,协程应用到爬虫的讲解
    python中with的用法
    为什么 Elasticsearch 需要堆内存来存储数据
    面向数据的架构
    跟我一起学Redis之看完这篇比常人多会三种类型实战(又搞了几个小时)
    跟我一起学.NetCore之熟悉的接口权限验证不能少(Jwt)
    跟我一起学.NetCore之WebApi接口裸奔有风险(Jwt)
  • 原文地址:https://www.cnblogs.com/lq67/p/11307359.html
Copyright © 2011-2022 走看看