asp.net Forms表单验证 使用经验及验证流程分析

简介:

      最近,要做一个登陆的页面,就想到了安全性方面的问题。记得曾经在邵志东老师讲的关于asp.net安全性方面的课程中,提到asp.net提供了4个身份验证程序:1.表单身份验证;2.Windows身份验证;3.Passport身份验证;4.默认身份验证。尤其讲了表单身份验证,想想,正好自己以前也不曾使用过这个验证方式,那就拿来练练手吧。

      表单验证,可以根据用户和角色来限制用户访问。比如,我们有以一个后台管理系统,只有通过后台登陆页面合法登陆的用户才能访问后台管理系统中的任何页面,这个时候我们就可以通过表单验证来实现(过去我都是在每一个页面写判断逻辑。现在想起来,过去的那种方法真是不折不扣的体力劳动,而且如果哪个页面忘记写了,就麻烦了)。

      实验开始(因为只记录经验,所以有些知识点这里并没有提到,需要大家多花点课外时间了。文末提供了些链接供大家参考)

      我接下来就来做一个Forms表单验证的例子。在该例子中,我建立了两个文件夹分别为User和Admin,在每一个文件夹中又有login.aspx、index.aspx和web.config。我希望普通用户访问User文件夹需要首先要在用户登陆界面进行登陆,成功后才能访问用户的index.aspx。而管理员则首先要在Admin的登陆界面进行登陆,才能访问Admin中的index.aspx。而在网站根目录有LoginRedirect.aspx、web.config和Global.asax。
      目录结构图:

       

      如何才能实现表单验证呢?
      1.配置根目录下的web.config (在网站根目录下web.config文件中的system.web标记中,修改原<authentication mode="Windows" />为如下代码)

ContractedBlock.gif Code

      上述的配置是什么意思呢?
      首先,这里有两个不同的配置节,authentication和authorization看上去是不是很像? 你可千万不要被眼睛欺骗了,这两个是不同的意思,前者是“验证”,后者是“授权”。
      接着,我们来看下“验证”这个配置节中的东西。
      mode表示的就是验证方式,这里有四个选项:Windows、Forms、Passport、None。默认的是Windows。我们这里选择Forms。
      而在forms元素里,设置了name和loginUrl。
      name表示cookie的名字,我们后面要通过cookie来保存一些用户信息并将包含cookie信息的http请求发送到服务器。服务器端,则会根据cookie信息对用户进行标识,从而进行进一步的验证。
      LoginUrl 顾名思义就是登陆页面的地址。如果说用户没有权限访问某一页面,就会被重定向到这个页面。

      还有其它诸多元素,请大家自己查找相关资料。我也会在文末给出一些我认为比较不错的链接。

      讲完了“验证”节,接着讲讲“授权”节。
      授权,自然是要限制哪些用户或角色可以访问,哪些用户或角色不能访问了。设置的方式就是通过设置<allow>和<deny>。如上所示的<allow users="*">就是表示允许所有用户访问。你可能会奇怪不是要限制用户访问吗,怎么全部允许了?那是因为,我就是希望“根目录下”的所有东西都可以被任何用户访问。

      再来看看两个子文件夹内的web.config。

ContractedBlock.gif User文件夹中的Web.config


      在这个配置文件中,不能配置“验证”节的内容(该内容只能在虚拟目录的根目录web.config中配置),我们只能对“授权”节进行配置。上述的location的作用是表示该路径不需要进行授权检查,因为我希望任何用户都可以进到登陆页面,原因大家应该都想得到吧。
      而其他路径,则不希望未登陆的用户或网站管理员登陆,因此使用<allow roles="user">来允许只有角色为user的用户访问,而其他任何用户都拒绝访问。
      同理,来看下管理员目录的web.config,请大家自己分析。

ContractedBlock.gif Admin目录的web.config

      配置好了之后,我们还需要写一些cs代码。首先我们来看一下loginRedirect.aspx.cs。因为,我们现在访问上述任何一个子文件的页面时,都会先跳转到这个页面里来,而其实我则希望可以跳到相信子目录的登陆页面中去。因此,需要在这个文件中进行一些判断。

ContractedBlock.gif Code

       有些人可能奇怪了,这么麻烦,既然可以在“验证”节中配置loginUrl,难道就不能对每个目录实现直接跳转到本目录相应登陆页面吗?很遗憾,目前为止,我还没有找到直接的解决办法。如果您有什么办法,请不吝赐教。
       跳转到登陆页面后,那我们就应该对用户的登陆时间进行处理了。

ContractedBlock.gif Code

      在Admin文件夹下的login.aspx.cs也是类似。就不再赘述了。
      差点忘了最后的一个东西了,就是为我们的用户配置角色。上面我们在创建票据的时候发现没有提供直接对角色赋值的功能,那我们就只能利用grobal.asax来实现了。
      在global.asax中有一个Application_AuthenticateRequest事件,该事件会在服务器决定该用户浏览器是否应该跳转前发生。因此,我们只要在这里对用户角色进行配置,就可以达到目的。

ContractedBlock.gif Application_AuthenticateRequest

      大家可以下载整个工程来看。
      【注意:不能在同一台电脑上即登陆用户界面又登陆管理员界面。因为使用Forms名称所能保留的cookie只可能是一个,所以如果登陆了管理员界面后,接着登陆用户界面,就会覆盖原来的cookie值。有些朋友使用session来保存用户数据的方法,为实验。】
      实验结束


      Forms验证流程
      大致页面处理流程如下:(介绍这个是为了引出FormsAuthenticationModule,因此不详细介绍,大家可以参考:ASP.NET页面生成流程
      客户端的http请求到达服务器端后,首先IIS会接收到该消息,然后调用asp.net isapi扩展,并由该扩展将请求等信息传送给.net运行时。.Net Runtime会调用ProcessRequest方法根据客户端发来的请求信息创建并初始化一个HttpWorkerRequest对象,并根据该对象创建HttpContext对象,该对象中包含HttpRequest、HttpResponse对象,其中HttpRequest对象中又包含cookie和浏览器信息。最终会生成并调用HttpApplication对象的Init方法。在Init方法中会调用HttpApplicaion.InitInternal方法。而该方法又会调用InitModules方法。InitModules方法则会初始化Web.Config中注册的所有模块(HttpModule)。

      我们的主角FormsAuthenticationModule也就是在这里上场了。
      初始化FormsAuthenticationModule的过程中,会先调用该Module的init方法。我们来看一下该方法中有些什么:

public   void  Init(HttpApplication app)
{
    app.AuthenticateRequest 
+=   new  EventHandler( this .OnEnter);
    app.EndRequest 
+=   new  EventHandler( this .OnLeave);
}

      Init方法注册了两个事件:OnEnter和OnLeave。分别在HttpApplication.AuthenticateRequest和EndRequst事件被触发时执行。
      这两个事件具体做了些什么呢? 
ContractedBlock.gif OnEnter

      在OnEnter事件中,我们提到一个重要的方法就是OnAuthenticate:
ContractedBlock.gif OnAuthenticate

      在执行了这个module之后,还有一个重要的module我们不得不提的就是UrlAuthorizationModule。在这个module中,对上面所设置的用户进行了授权检查,来确定该用户是否可以访问所请求的页面。如果用户没有权限,则跳转到loginUrl中所指定的页面。主要方法就是OnEnter:
ContractedBlock.gif OnEnter
      前面我们介绍了,FormsAuthenticationModule中的2个主要事件中注册了2个方法。这里来说第二个OnLeave方法。在这个方法中才真正设置了跳转的页面。
ContractedBlock.gif OnLeave

      根据这个流程,结合前面的实验,我们来模拟以下这个执行过程。
      下述a~o这些步骤大致描述了整个验证的执行流程。其中涉及到一些Http协议的知识:(这里介绍几个)
      每次我们请求一个页面,就是在发送一个http请求。在这个请求中包含了我们请求的方式(主要是Get、Post)、请求的页面地址、客户端的浏览器信息、Cookie等。而发送一次请求之后,服务器都会返回一个Http应答包。在这个包中会有一些表示状态的代码,比如我们常见的404、200等,而表示跳转的状态代码则是302。另外,如果服务器需要在客户端设置cookie的话会在应答包的包头中加入set-cookie。具体例子如下:



上图为一次Http请求 

 


上图为一次Http应答


      对Http协议有所了解后,现在来假设是第一次访问用户文件夹中的index.aspx页面。那这个过程就如下所示:
      a.由于是第一次访问这个站点,浏览器无法在本地找到与这个网站对应的cookie,因此会发送一个cookie为空的http请求到服务器端。
      b.服务器的IIS在接受到此请求后,会交给asp.net isapi扩展进行处理。.net 运行时会为这个请求创建一个HttpApplication对象。
      c.HttpApplication对象创建后,会执行Init()方法,从而执行了FormsAutheticationModule。
      d.在执行该模块的过程中首先会读取web.config中的配置信息配置loginUrl等数据。
      e.接着会触发OnAuthenticate方法,该方法首先执行gloabl.aspx中的Application_AuthenticateRequest事件,不过往往由于此时用户还并未通过验证,所以在这次请求中,前面global.asax所写的内容执行不到。接着就会检查用户是否通过验证,本次请求显然是没有通过验证。
      f.在UrlAuthorizationModule中,首先从web.config中读取配置信息,然后核对用户。由于e中用户没有通过验证,因此这里肯定核对失败。于是会执行context.Response.StatusCode = 0x191
      g.最后执行到FormsAutheticationModule的OnLeave事件,因为context.Response.StatusCode == 0x191所以设置用户浏览器需要执行跳转。这个实现的方式,是通过http应答包返回302指令(跳转指令),并设置了http头的Location为目的页面。
      h.浏览器在接受到返回的http应答包后,执行跳转。此时目标为LoginRedirect.aspx。(同样有是一次对loginredirect.aspx的请求,过程省略)。
      i .由于我们在LoginRedirect.aspx.cs中也是一个跳转,因此请求这个页面所返回的Http应答包同样是一个跳转指令(跳转到用户登陆的界面Login.aspx)。
      j .输入用户名,密码单击登陆,又发送了一次http请求到服务器端。但是这次包含了用户的登陆数据是按Post方式发送的。
      k.由于此时用户并没有审核通过,所以仍旧执行上面的a~d,由于login.aspx这个页面在配置文件中我们是设置为[location]节中,因此在后面的验证中就是一路绿灯呀。执行完了所有module后的,此时的http应答包中并不包含跳转指令。
      l.接着执行在login.aspx.cs中定义的事件,在该事件中,对用户的登陆信息进行验证,如果验证通过,则设置验证票据,并将其值保存在cookie中,同时在http应答包中加入cookie。也就是执行Response.Cookie.Add(); 并且,还在事件最后要求浏览器跳转到index.aspx。这便又在http应答包中加入了跳转指令
      m.浏览器在接收到这个http应答包后,提取其中的cookie,并保存在本地。同时跳转到相应页面(又发起一次对index.aspx页面的请求)。
      n.在新的请求发出之前,浏览器由于找到了该站点对应的cookie,会把该cookie值加入到请求中发送到服务器。
      o.后续的步骤其实又执行了一遍上述过程,但是这次在验证的时候,因为有了传入的cookie,可以得到合法用户的信息,也就通过了验证。

      流程介绍结束

      写的不当之处,希望大家直言不讳~~

      整个工程下载http://files.cnblogs.com/stg609/LoginAuthentication.rar(开发平台:VS 2008. 不过,基本没用到.net 3.0的东西,可能可以顺利转换到VS 2005上使用)

      推荐阅读http://www.cnblogs.com/cuihongyu3503319/archive/2008/09/11/1288956.html
                     http://book.csdn.net/bookfiles/406/10040614811.shtml
                     http://www.codeproject.com/KB/web-security/formsroleauth.aspx
                     http://blog.csdn.net/virone/archive/2008/04/12/2284173.aspx
                     手把手教你HTTP协议之Session和Cookie






本文转自stg609博客园博客,原文链接:http://www.cnblogs.com/stg609/archive/2009/03/12/1408296.html,如需转载请自行联系原作者

目录
相关文章
|
5月前
|
网络协议 算法 Shell
来我们探究一下net/http 的代码流程
来我们探究一下net/http 的代码流程
|
1月前
|
开发框架 搜索推荐 .NET
ASP.NET体检中心源码,实现检前、检中、检后全流程管理
健康体检系统遵循整个健康体检的实际流程,以提高工作效率、降低错检、防止漏检提高人性化服务水平为目的,在体检过程中可以高效、自动化、人性化的处理数据与提供服务。针对体检流程中工作强度在时间分配上不均匀等特点,解决了体检信息处理效率问题,在不增加体检中心人力资源投入或少投入的基础上,提升信息处理的效率,从而突破体检中心日处理体检人数的上限,为体检中心创造更大经济效益的同时,还能有效的降低体检工作者的劳动强度。
36 5
|
4月前
|
数据库
VB.NET 三层登录系统实战:从设计到部署全流程详解
VB.NET 三层登录系统实战:从设计到部署全流程详解
57 0
|
9月前
|
开发框架 JSON 算法
ASP.NET Core Web API之Token验证
ASP.NET Core Web API之Token验证
145 0
|
9月前
|
网络协议 Shell Go
来我们一起探究一下net/http 的代码流程
是GO的其中一个标准库,用于Web应用的开发,使用这个库,可以让开发变得更加迅速和简便,且易于上手
|
10月前
|
开发框架 安全 .NET
[牛腩]如何关闭.net framework4.0的请求验证
[牛腩]如何关闭.net framework4.0的请求验证
72 0
|
存储 开发框架 前端开发
ASP.NET 中验证的自定义返回和统一社会信用代码的内置验证实现
本文介绍 ASP.NET 中内置的验证功能,并介绍如何自定义验证返回信息,最后以统一社会信用代码为例,实现自定义的数据验证。
188 0
ASP.NET 中验证的自定义返回和统一社会信用代码的内置验证实现
|
小程序 安全 API
.NET企业微信回调配置(数据回调URL和指令回调URL验证)(一)
.NET企业微信回调配置(数据回调URL和指令回调URL验证)
804 0
.NET企业微信回调配置(数据回调URL和指令回调URL验证)(一)
|
存储 开发框架 Java
【CLR C#】浅谈.Net的GC(垃圾回收)机制及其整体流程
在.NET程序开发中,为了将开发人员从繁琐的内存管理中解脱出来,将更多的精力花费在业务逻辑上,CLR提供了自动执行垃圾回收的机制来进行内存管理,开发人员甚至感觉不到这一过程的存在。.NET程序可以找出某个时间点上哪些已分配的内存空间没有被程序使用,并自动释放它们。自动找出并释放不再使用的内存空间机制,就称为垃圾回收机制。本文主要介绍.Net中的GC(垃圾回收)机制及其整体流程。
【CLR C#】浅谈.Net的GC(垃圾回收)机制及其整体流程
|
开发框架 JSON 前端开发
ASP.NET MVC5----常见的数据注解和验证
ASP.NET MVC5----常见的数据注解和验证
300 0
ASP.NET MVC5----常见的数据注解和验证

相关实验场景

更多