您的位置:首页 > 编程语言 > ASP

Asp.Net实现FORM认证的一些使用技巧(转)

2016-07-16 20:20 561 查看
最近因为项目代码重构需要重新整理用户登录和权限控制的部分,现有的代码大体是参照了.NET的FORM认证,并结合了PORTAL KITS的登录控制,代码比较啰嗦,可维护性比较差。于是有了以下的几个需求(大多数系统应该都会碰到):

用.NET自带的FORM认证来实现安全登录

登录后需要记录登录用户的基本信息,方便所有页面调用

记录本机登录状态,短时间关闭窗口后不用重新登录

权限控制和代码的文件夹结构相呼应,即按角色允许访问不同的目录

权限控制有可能需要细化到每一个页面,即按角色允许访问不同的页面

以上的部分尽量自己少写代码,用自带的类库和机制实现

第一步:准备工作

先准备一个名为Test的WEB项目,包含:

Default.aspx,默认页,随便显示一些信息,

Login.aspx,登录页,上面放两个文本框,用来输入用户名和密码,一个登录按钮,一个指向Register.aspx的超链,

Register.aspx,用户注册页,注册用户信息,随便放一点文本框,主要是模拟一下注册,不用真正实现,

Web.config,配置页面。

注册页与登录页在同一目录的机妙后面会说。

第二步:Web.config文件的修改

  1、打开Web.config文件,找到authentication节,将其改为如下:

代码

  上面的代码,实际上类似于手工实现了SetAuthCookie方法的过程。

  首先,模拟实现登录,我们手动设置了一个UserInfo的对象,string strUser = Serialize.Encrypt<UserInfo>(user) 是将对象序列化成字符串的一个方法。

  然后,生成一个FormsAuthenticationTicket票据。此处用到的FormsAuthenticationTicket构造函数的重载方法的签名解释

代码

  其中,name的设置与Context.User.Identity.Name对应,且大小写敏感,也与将来的权限控制相关,赋值的时候需要特别注意。另外,票据的到期日期和Web.config中设置的Cookie的到期日期不是同一个概念,如果分不清,请到网上去搜索,如果实在不想在这上下功夫,后面会有处理的方法。

  再后,string strTicket = FormsAuthentication.Encrypt(ticket) 将票据加密成字符创

  最后,HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, strTicket) 生成Cookie。
FormsAuthentication.FormsCookieName获取的就是Web.config中配置的Cookie名称,也就是默认验证时产生的Cookie。cookie.Expires = ticket.Expiration 将票据的过期时间和Cookie的过期时间做了同步,也就避免了两者不同所产生的矛盾。这样,验证票据生成了,存储到默认配置的Cookie中,也就是类似实现了一个SetAuthCookie方法的过程。通过Context.User就能获取票据的相关信息了。

  

  3、获取信息

  为了在其他登录后的页面比较简单的获取登录用户信息,我们先生成一个基类页面。在AppCode中新增LoginBasePage类,代码如下:

代码

  再将文件夹ManageAdmin下的Web.config文件的<allow users="Admin"></allow>改成<allow roles="Administrators"></allow>。

  最后,修改代码。

  1、注意,我们在模拟用户信息的时候,有这么一句,user.Roles = "Administrators,Users";也就是用户Admin具备两种角色

  2、为模拟Users组的用户登录,我们再添加如下代码:

代码

  这样,我们登录时,输入“Admin”和“User1”的时候,就可以模拟不同角色的用户登录了。

  3、Forms基于角色的验证的内部机制是,将角色的属性也设置到了Context.User中,这里也需要手工代码处理一下。        

  首先,为了支持基于角色的验证,我们每进入一个页面都需要将角色信息设置到Context.User中,那么最好的办法就是在Global.asax 文件中的Application_AuthenticateRequest方法中设置。

  Application_AuthenticateRequest方法,是在每次验证请求时触发,它与另外一个方法
Application_BeginRequest的区别就在于,Application_AuthenticateRequest方法内,能够访问
Context.User.Identity,而Application_BeginRequest则无法访问。

  我们在根目录添加一个Global.asax 文件,增加如下代码:

代码

  此处,主要代码就是将Context.User.Identity强制转换为FormsIdentity类的对象,通过访问Ticket属性的UserData属性,获得被序列化后的对象的字符串,最后用方法Serialize.Decrypt<UserInfo>(strUser)将字符串反序列化成对象,再将UserInfo对象的Roles属性以“,”为分隔符分隔成角色数组,再用Context.User.Identity和角色数组生成一个新的GenericPrincipal对象,赋值给Context.User ,则Context.User 为已经设置好角色的验证对象。

  按照我们的设置,Admin用户能访问两个目录,而User1用户,则只能访问ManageUsers一个目录。

第五步:集中管理Web.config文件

  目录的访问权限控制,是按用户还是按角色,一般由具体业务决定。

  但是,随着目录的增多,每个目录下都存在一个Web.config文件,管理起来特别不方便。

  通过上面提到过的location节的path属性,我们可以实现Web.config配置的统一管理。我们可以将各个文件或目录的配置都放置在根目录的Web.config文件内,代码如下:

<configuration>
<appSettings/>
<connectionStrings/>

<location path ="Register.aspx">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>

<location path ="ManageAdmin">
<system.web>
<authorization>
<allow roles="Administrators"></allow>
<deny users="*"></deny>
</authorization>
</system.web>
</location>

<location path ="ManageUsers">
<system.web>
<authorization>
<allow roles="Users"></allow>
<deny users="*"></deny>
</authorization>
</system.web>
</location>

<system.web>
<!-- 这里放置原来根目录 Web.config 的内容,就不列出来了 -->
</system.web>

</configuration>

结尾:

  这次彻底理顺FORM验证的过程,发现了不少实用性很强的技巧,中间参考了很多网友的文章,也通过Reflector看了一下具体实现的源代码。感觉收获不少,最大的收获就是对于问题不但要知其然更要知其所以然,要有一种打破沙锅问到底的净胜。

  大家如果有什么问题有什么疑问,不但要找到解决的办法,有时间的话最好从理论到底层代码都好好过一过,对自己的水平长进有很大的帮助。

  这篇文章还有很多方面没有涉及,也有很多高深的东西没有讲到,例如“通过PrincipalPermissionAttribute配合Forms验证进行基于角色或用户的安全验证”。就当留给自己一个研究的尾巴吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: