search
Homephp教程php手册(转贴)一套.net窗体身份验证方案(解决了防止用户重复登陆,sessio

http://blog.csdn.net/johnsontj/articles/324369.aspx 一. 设置 web.config 相关选项 先启用窗体身份验证和默认登陆页,如下。 authenticationmode="Forms" formsloginUrl="default.aspx"/forms /authentication 设置网站可以匿名访问,如下 authorization

http://blog.csdn.net/johnsontj/articles/324369.aspx

 

一.      设置web.config相关选项 

 

先启用窗体身份验证和默认登陆页,如下。

 

 

       

 

 

设置网站可以匿名访问,如下

 

 

           

 

 

 

 

 

然后设置跟目录下的admin目录拒绝匿名登陆,如下。注意这个小节在System.Web小节下面。

 

     

 

       

 

           

 

              

 

           

 

       

 

 

把http请求和发送的编码设置成GB2312,否则在取查询字符串的时候会有问题,如下。

 

 

设置session超时时间为1分钟,并启用cookieless,如下。

 

 

为了启用页面跟踪,我们先启用每一页的trace,以便我们方便的调试,如下。

 

 

 

二.      设置Global.asax文件

 

处理Application_Start方法,实例化一个哈西表,然后保存在Cache里

 

    protected void Application_Start(Object sender, EventArgs e)

 

    {

 

       Hashtable h=new Hashtable();

       Context.Cache.Insert("online",h);

}

    在Session_End方法里调用LogoutCache()方法,方法源码如下

 

/// 

    /// 清除Cache里当前的用户,主要在Global.asax的Session_End方法和用户注销的方法里调用      /// 

    public void LogoutCache()

   {

 

      Hashtable h=(Hashtable)Context.Cache["online"];

       if(h!=null)

       {

           if(h[Session.SessionID]!=null)

           h.Remove(Session.SessionID);

           Context.Cache["online"]=h;

       }

}

 

三.      设置相关的登陆和注销代码

 

登陆前调用PreventRepeatLogin()方法,这个方法可以防止用户重复登陆,如果上次用户登陆超时大于1分钟,也就是关闭了所有admin目录下的页面达到60秒以上,就认为上次登陆的用户超时,你就可以登陆了,如果不超过60秒,就会生成一个自定义异常。在Cache["online"]里保存了一个哈西表,哈西表的key是当前登陆用户的SessionID,而Value是一个ArrayList,这个ArrayList有两个元素,第一个是用户登陆的名字第二个元素是用户登陆的时间,然后在每个admin目录下的页刷新页面的时候会更新当前登陆用户的登陆时间,而只admin目录下有一个页打开着,即使不手工向服务器发送请求,也会自动发送一个请求更新登陆时间,下面我在页面基类里写了一个函数来做到这一点,其实这会增加服务器的负担,但在一定情况下也是一个可行的办法.

 

/// 

 

       /// 防止用户重复登陆,在用户将要身份验证前使用

       /// 

       /// 要验证的用户名字

       private void PreventRepeatLogin(string name)

       {

           Hashtable h=(Hashtable)Cache["online"];

           if(h!=null)

           {

              IDictionaryEnumerator e1=h.GetEnumerator();

 

              bool flag=false;

 

              while(e1.MoveNext())

              {    

                  if((string)((ArrayList)e1.Value)[0]==name)

                  {

                     flag=true;

 

                     break;

                  }

              }

              if(flag)

              {

                  TimeSpan ts=System.DateTime.Now.Subtract(Convert.ToDateTime(((ArrayList)e1.Value)[1]));

                  if(ts.TotalSeconds

                     throw new oa.cls.MyException("对不起,你输入的账户正在被使用中,如果你是这个账户的真正主人,请在下次登陆时及时的更改你的密码,因为你的密码极有可能被盗窃了!");

                  else

                     h.Remove(e1.Key);    

              }

           }

           else

           {

              h=new Hashtable();

           }

           ArrayList al=new ArrayList();

           al.Add(name);

           al.Add(System.DateTime.Now);

           h[Session.SessionID]=al;

           if(Cache["online"]==null)

           {

              Context.Cache.Insert("online",h);

           }else

              Cache["Online"]=h; 

    }

 

用户注销的时候调用上面提到LogoutCache()方法

 

四.      设置admin目录下的的所有页面的基类

 

using System;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

using System.Collections;

namespace oa.cls

{

    public class MyBasePage : System.Web.UI.Page

    {

       /// 

       /// 获取本页是否在受保护目录,我这里整个程序在OA的虚拟目录下,受保护的目录是admin目录

       /// 

       protected bool IsAdminDir

       {

           get

           {

              return Request.FilePath.IndexOf("/oa/admin")==0;

           }

       }

 

       /// 

       /// 防止session超时,如果超时就注销身份验证并提示和转向到网站默认页

       /// 

       private void PreventSessionTimeout()

       {

           if(!this.IsAdminDir) return;

           if(Session["User_Name"]==null&&this.IsAdminDir)

           {   

 

             System.Web.Security.FormsAuthentication.SignOut();

 

              this.Alert("登陆超时",Request.ApplicationPath)

           }

       }

       /// 

 

       /// 每次刷新本页面的时候更新Cache里的登陆时间选项,在下面的OnInit方法里调用.

       /// 

       private void UpdateCacheTime()

       {

           Hashtable h=(Hashtable)Cache["online"];

           if(h!=null)

           {

              ((ArrayList)h[Session.SessionID])[1]=DateTime.Now;

           }

 

           Cache["Online"]=h;

 

       }

 

       /// 

       /// 在跟踪里输出一个HashTable的所有元素,在下面的OnInit方法里调用.以便方便的观察缓存数据

       /// 

       /// 

       private void TraceValues( Hashtable myList) 

       {

           IDictionaryEnumerator myEnumerator = myList.GetEnumerator();

           int i=0;

           while ( myEnumerator.MoveNext() )

           {

              Context.Trace.Write( "onlineSessionID"+i, myEnumerator.Key.ToString());

              ArrayList al=(ArrayList)myEnumerator.Value;

              Context.Trace.Write( "onlineName"+i, al[0].ToString());

              Context.Trace.Write( "onlineTime"+i,al[1].ToString());

              TimeSpan ts=System.DateTime.Now.Subtract(Convert.ToDateTime(al[1].ToString()));

               Context.Trace.Write("当前的时间和此登陆时间间隔的秒数",ts.TotalSeconds.ToString());

              i++;

           }

       }

 

       /// 

       /// 弹出信息并返回到指定页

       /// 

       /// 弹出的消息

       /// 指定转向的页面

       protected void Alert(string msg,string url)

       {

           string scriptString = "<script>alert(/""+msg+"/");location.href=/""+url+"/"</script>";

           if(!this.IsStartupScriptRegistered("alert"))

              this.RegisterStartupScript("alert", scriptString);

       }

 

       /// 

       /// 为了防止常时间不刷新页面造成会话超时,这里写一段脚本,每隔一分钟向本页发送一个请求以维持会话不被超时,这里用的是xmlhttp的无刷新请求

       /// 这个方法也在下面的OnInit方法里调用

       /// 

       protected void XmlReLoad()

       {     

           System.Text.StringBuilder htmlstr=new System.Text.StringBuilder();

           htmlstr.Append("

           htmlstr.Append("function GetMessage(){");

           htmlstr.Append("  var xh=new ActiveXObject(/"Microsoft.XMLHTTP/");");

           htmlstr.Append("  xh.open(/"get/",window.location,false);");

           htmlstr.Append("  xh.send();");

           htmlstr.Append("  window.setTimeout(/"GetMessage()/",60000);");

           htmlstr.Append("}");

           htmlstr.Append("window.onload=GetMessage();");

           htmlstr.Append("       ");

           if(!this.IsStartupScriptRegistered("xmlreload"))

              this.RegisterStartupScript("alert", htmlstr.ToString());

       }

       override protected void OnInit(EventArgs e)

       {

 

           base.OnInit(e);

           this.PreventSessionTimeout();

           this.UpdateCacheTime();

           this.XmlReLoad();

           if(this.Cache["online"]!=null)

           {

              this.TraceValues((System.Collections.Hashtable)Cache["online"]);

           }

       }

    }

}

 

五.      写一个自定义异常类

 

首先要在跟目录下写一个错误显示页面ShowErr.aspx,这个页面根据传递过来的查询字符串msg的值,在一个Label上显示错误信息。

 

 

using System;

namespace oa.cls

{

    /// 

    /// MyException 的摘要说明。

    /// 

    public class MyException:ApplicationException

    {

           /// 

           /// 构造函数

           /// 

           public MyException():base()

           {

 

           }

           /// 

           /// 构造函数

           /// 

           /// 异常消息

           public MyException(string Message):base(Message)

           {

               System.Web.HttpContext.Current.Response.Redirect("~/ShowErr.aspx?msg="+Message);

           }

 

           /// 

           /// 构造函数

           /// 

           /// 异常消息

           /// 引起该异常的异常类

           public MyException(string Message,Exception InnerException):base(Message,InnerException)

          {

           }

       }

} 

 

 

六.总结

我发现在Session里保存的值,比如session["name"]是没有任何向服务器的请求达到1分钟后就会自动丢失,但是session ID是关闭同一进程的浏览器页面后达1分钟后才会丢失并更换的,因为只要你开着浏览器就会有session ID,无论是在url里保存还是在cookies里。不知道这个结论对不对,反正我在设置了session的timeout为1分钟后,session["name"]的值已经没有了,可是SessionID还是旧的,Global.asax里的Session_End里的代码也没有执行,而身份验证票据也没有丢失。我不知道这三者之间的关系是怎样的,谁先谁后,好像在小节可以设置一个timeout属性,不过项目赶的紧,我没时间研究了。

 

以上这些代码比较零散,我花费了2天的时间才总结出来这套方案,不是很完美,但是暂时只能这样了,不能在这方面浪费很多时间了,大家可以把上面的代码组织到一个类里,然后把方法都修改成静态方法方便调用

 

最后大家有什么建议和改进的意见欢迎和我交流。

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
golang中如何验证输入是否为大写字母golang中如何验证输入是否为大写字母Jun 24, 2023 am 09:06 AM

Golang是一门高性能、现代化的编程语言,在日常开发中经常涉及到字符串的处理。其中,验证输入是否为大写字母是一个常见的需求。本文将介绍在Golang中如何验证输入是否为大写字母。方法一:使用unicode包Golang中的unicode包提供了一系列函数来判断字符的编码类型。对于大写字母,其对应的编码范围为65-90(十进制),因此我们可以使用unicod

分享几个.NET开源的AI和LLM相关项目框架分享几个.NET开源的AI和LLM相关项目框架May 06, 2024 pm 04:43 PM

当今人工智能(AI)技术的发展如火如荼,它们在各个领域都展现出了巨大的潜力和影响力。今天大姚给大家分享4个.NET开源的AI模型LLM相关的项目框架,希望能为大家提供一些参考。https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel是一种开源的软件开发工具包(SDK),旨在将大型语言模型(LLM)如OpenAI、Azure

C#的就业前景如何C#的就业前景如何Oct 19, 2023 am 11:02 AM

无论您是初学者还是有经验的专业人士,掌握C#将为您的职业发展铺平道路。

golang中如何验证输入是否为全角字符golang中如何验证输入是否为全角字符Jun 25, 2023 pm 02:03 PM

在golang中,验证输入是否为全角字符需要用到Unicode编码和rune类型。Unicode编码是一种将字符集中的每个字符分配一个唯一的数字码位的字符编码标准,其中包含了全角字符和半角字符。而rune类型是golang中用于表示Unicode字符的类型。第一步,需要将输入转换为rune类型的切片。这可以通过使用golang的[]rune类型进行转换,例如

PHP正则表达式验证特定字符串开头结尾的方法PHP正则表达式验证特定字符串开头结尾的方法Jun 24, 2023 am 11:20 AM

PHP是一种非常流行的编程语言,常用于Web开发。在PHP开发中,我们经常会遇到需要验证字符串的情况。其中,正则表达式是一种非常常用的方法。在对字符串进行验证时,我们经常需要验证字符串是否以特定字符或字符串开头或结尾。本文将介绍如何使用PHP正则表达式来验证字符串的开头或结尾。验证字符串开头在PHP中,通过正则表达式验证字符串开头,我们可以使用"^"符号来表

golang中如何验证输入是否全部为中文字符golang中如何验证输入是否全部为中文字符Jun 24, 2023 am 09:16 AM

随着时代的发展,我们越来越注重对数据的校验,特别是对用户输入的校验。对于语言类的校验,如何准确判定输入是否全部为中文字符成为了一个重要问题。而在golang中,我们可以借助unicode包和regexp包来实现这一需求。一、unicode包unicode包提供了一系列对于unicode的核心支持。我们可以使用这个包中的函数来准确地判断一个字符是否为中文字符。

在PHP中使用Google reCAPTCHA进行验证在PHP中使用Google reCAPTCHA进行验证Jun 19, 2023 pm 05:38 PM

在现代网络世界中,网站的安全性以及用户隐私的保护越来越成为重要话题。其中,人机验证这一技术方法已经成为防范恶意攻击行为的不可或缺的方式之一。GooglereCAPTCHA,是一个被广泛应用于人机验证的工具,其概念已经深入人心,甚至在我们每天使用的许多网站上都能够看到其存在的身影。在本文中,我们将探讨如何在PHP中使用GooglereCAPTCHA进行验证

PHP正则表达式验证正整数的方法PHP正则表达式验证正整数的方法Jun 24, 2023 am 08:55 AM

在PHP中,正则表达式可以用于验证和处理字符串。验证正整数的正则表达式如下所示:$pattern=&quot;/^[1-9]d*$/&quot;;其中,^表示开头,$表示结尾,[1-9]表示第一个字符必须是1-9之间的数字,d表示其他字符必须是数字,*表示0个或多个。因此,这个正则表达式可以匹配任意一个正整数。下面是一个完整的例子,演示如何使用正则表达式

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

Repo: How To Revive Teammates
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version