zoukankan      html  css  js  c++  java
  • 单点登录的一系列尝试及最终解决

    曾经一时兴起,想搞一个实现单点登录的,然后实现起来发现了好多问题,首先原理明白,代码也很好写,如下:

    Default.aspx

    <%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"%>

    <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server">

    </asp:Content>

    <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">

    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

    <br />

    <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>

    <br />

    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="登陆" />

    <asp:Button ID="Button2" runat="server" OnClick="Button2_Click" Text="注销" />

    </asp:Content>

    Default.aspx.cs

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.Caching;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    public partial class _Default : System.Web.UI.Page

    {

    protected void Page_Load(object sender, EventArgs e)

    {

    }

    protected void Button1_Click(object sender, EventArgs e)

    {

    // 作为唯一标识的str_Key,应该是唯一的,这可根据需要自己设定规则。

    // 做为测试,这里用用户名和密码的组合来做标识;也不进行其它的错误检查。

    // 生成str_Key

    string str_Key = TextBox1.Text + " " + TextBox2.Text;

    // 得到Cache中的给定str_Key的值

    string str_User = Convert.ToString(Cache[str_Key]);

    // Cache中没有该str_Key的项目,表名用户没有登录,或者已经登录超时

    if (str_User == String.Empty)

    {

    // TimeSpan构造函数,用来重载版本的方法,进行判断是否登录。

    TimeSpan SessTimeOut = new TimeSpan(0, 0, HttpContext.Current.Session.Timeout, 0, 0);

    HttpContext.Current.Cache.Insert(str_Key, str_Key, null, DateTime.MaxValue, SessTimeOut, CacheItemPriority.NotRemovable, null);

    Session["User"] = str_Key;

    // 首次登录成功

    Response.Write("<h2 style='color:red'>你好,登录成功!");

    }

    else

    {

    // 在 Cache 中存在该用户的记录,表名已经登录过,禁止再次登录

    Response.Write("<h2 style='color:red'>抱歉,您好像已经登录了!");

    return;

    }

    }

    protected void Button2_Click(object sender, EventArgs e)

    {

    Response.Redirect("Default2.aspx");

    }

    }

    实现效果如下:

    重复登录

    注销之后再登录

    但是往往有些用户的习惯是不会去管注销,退出一类的按钮,而是直接选择关闭浏览器,从而就会导致一类问题,我们学校的老的一款选课系统也是这样,不点注销直接关浏览器,下次登录就只能半小时后了,为了解决这个问题曾经查过很多资料,大体思路就是如何在用户关闭浏览器的时候直接清除掉session,从而是cache失去依赖项而被移除,思路上是正确的,但是随之而来的一个巨大难点是如何判断用户关闭了浏览器。从而进行了很多尝试,如下:

    1. dom里面有一个属性closed,当它为true时即浏览器窗口window关闭,但用过之后发现,这样是没办法区分刷新和关闭的,因为刷新是先close,再open,从而宣告这个方法失败。
    2. 用js判断,代码如下:

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

      <html xmlns="http://www.w3.org/1999/xhtml">

      <head>

      <title>Js智能判断浏览器是关闭还是刷新</title>

      <meta http-equiv="content-type" content="text/html;charset=gb2312">

      </head>

      <body>

      关闭或刷新浏览器试试!

      <script language="javascript">

      window.onbeforeunload=function(){

          var n=window.event.screenX-window.screenLeft;

          var b=n>document.documentElement.scrollWidth-20;

          if(b&&window.event.clientY<0||window.event.altKey){

              alert("关闭");

          }else{

              alert("刷新");

          }

      }

      </script>

      </body>

      </html>

      最终测试结果失败的彻彻底底,刷新事件部分浏览器能判断出来,但是关闭事件所有浏览器都无法判断

    3. 用ajax延迟判断,如一所说,dom有一个关闭属性,关闭是直接close为true,刷新则是先close,再open,我可以在页面加载的时候就open一个高和宽都为0的不可见的窗口,里面用timer将事件的判断延迟处理一下,一般来说刷新的close和open是连在一起的,所以只需要延迟几毫秒,判断有没有调用open就可以了。最后测试方法可行,但是这样会非常耗资源,给用户和服务器带来不必要的压力,不推荐使用。
    4. 心跳包算法,即页面打开后隔一段时间给服务器发一个空包,让服务器知道这个页面还活着,当用户关闭浏览器,即停止发包,心跳停止,服务器认为页面已死,清除掉session。这个得涉及到比较高端的用法,新手不建议用,很容易因为发包不当而导致ddos攻击。
    5. 结合cookie和session,cookie不设置过期时间,即为浏览器的生命周期,关闭浏览器就会清除,结合它二者判断。这是我目前找到的最有用的方法,但由于cookie是保存在用户端的,会有一些安全隐患。

    昨晚趁学长在问了一下学长,才发现自己的思维一直进入了一个误区,其实没必要用户关闭浏览器就清除session,当用户关闭浏览器,然后在session过期前再次打开页面的时候,直接让用户跳过登陆,仔细想想新浪和腾讯可不就是这么干的么,最后的实现代码如下:

    Default.aspx.cs

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.Caching;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    public partial class _Default : System.Web.UI.Page

    {

    protected void Page_Load(object sender, EventArgs e)

    {

    if (!IsPostBack)

    {

    string str_User = Convert.ToString(Cache[Convert.ToString(Session["User"])]);

    // Cache中没有该str_Key的项目,表名用户没有登录,或者已经登录超时

    if (str_User != String.Empty)

    {

    Response.Write("<h2 style='color:red'>你好,登录成功!");

    }

    }

    }

    protected void Button1_Click(object sender, EventArgs e)

    {

    // 作为唯一标识的str_Key,应该是唯一的,这可根据需要自己设定规则。

    // 做为测试,这里用用户名和密码的组合来做标识;也不进行其它的错误检查。

    // 生成str_Key

    string str_Key = TextBox1.Text + " " + TextBox2.Text;

    // 得到Cache中的给定str_Key的值

    string str_User = Convert.ToString(Cache[str_Key]);

    // Cache中没有该str_Key的项目,表名用户没有登录,或者已经登录超时

    if (str_User == String.Empty)

    {

    // TimeSpan构造函数,用来重载版本的方法,进行判断是否登录。

    TimeSpan SessTimeOut = new TimeSpan(0, 0, HttpContext.Current.Session.Timeout, 0, 0);

    HttpContext.Current.Cache.Insert(str_Key, str_Key, null, DateTime.MaxValue, SessTimeOut, CacheItemPriority.NotRemovable, null);

    Session["User"] = str_Key;

    // 首次登录成功

    Response.Write("<h2 style='color:red'>你好,登录成功!");

    }

    else

    {

    // 在 Cache 中存在该用户的记录,表名已经登录过,禁止再次登录

    Response.Write("<h2 style='color:red'>抱歉,您好像已经登录了!");

    return;

    }

    }

    protected void Button2_Click(object sender, EventArgs e)

    {

    Response.Redirect("Default2.aspx");

    }

    }

    最后实现的效果是登陆之后不注销,关闭窗口,然后再打开,就会自动登录了,截图

    至此单点登录问题暂时告一段落

  • 相关阅读:
    Leap Ftp 3.0注册码
    Access数据库导入到MSSQLServer数据库中的三种办法。
    flash上传插件uploadify详解_图片批量上传_更新数据库
    Winform(c#)手机号码归属地查询的实现
    百度再度出现故障,目前很多地区无法正常访问!
    windows 2000/2003 自动重启/定时重启
    js初步学习
    考研之三战讨论
    C++中的map学习
    BUPT 63T 高才生 找最佳基站
  • 原文地址:https://www.cnblogs.com/xzjs/p/3073780.html
Copyright © 2011-2022 走看看