Forms身份验证基本原理

要采用Forms身份验证,先要在应用程序根目录中的Web.config中做相应的设置:

<authentication mode="forms">
    <forms name=".ASPXAUTH " loginUrl="/login.aspx" timeout="30" path= "/">
    </forms>
</authentication>

<forms>标签中的name表示指定要用于身份验证的HTTP Cookie(即指定Cookie名字),默认值是.ASPXAUTH

.ASPXAUTH这个使用来决定用户是否被认证了,即验证用户

采用此种方式验证用户后,以此用户的信息建立一个FormsAuthenticationTicket类型的身份验证票,再加密序列化为一个字符串,最后将这个字符串写到客户端的name指定名字的Cookie中.一旦这个Cookie写到客户端后,此用户再次访问这个web应用时会将连同Cookie一起发送到服务端,服务端将会知道此用户是已经验证过的.

<forms>标签中的loginUrl指定如果没有找到任何有效的身份验证 Cookie,为登录将请求重定向到的 URL。默认值为 default.aspx。loginUrl指定的页面就是用来验证用户身份的,一般此页面提供用户输入用户名和密码,用户提交后由程序来根据自己的需要来验证用户的合法性(大多情况是将用户输入信息同数据库中的用户表进行比较),如果验证用户有效,则生成同此用户对应的身份验证票,写到客户端的Cookie,最后将浏览器重定向到用户初试请求的页面.一般是用FormsAuthentication.RedirectFromLoginPage 方法来完成生成身份验证票,写回客户端,浏览器重定向等一系列的动作.

public static void RedirectFromLoginPage( string userName, bool createPersistentCookie, string strCookiePath );
其中:
userName: 就是此用户的标示,用来标志此用户的唯一标示,不一定要映射到用户账户名称.
createPersistentCookie: 标示是否发出持久的 Cookie。
若不是持久Cookie,Cookie的有效期Expiration属性有当前时间加上web.config中timeout的时间,每次请求页面时,在验证身份过程中,会判断是否过了有效期的一半,要是的话更新一次cookie的有效期;若是持久cookie,Expiration属性无意义,这时身份验证票的有效期有cookie的Expires决定,RedirectFromLoginPage方法给Expires属性设定的是50年有效期。
strCookiePath: 标示将生成的Cookie的写到客户端的路径,身份验证票中保存这个路径是在刷新身份验证票Cookie时使用(这也是生成Cookie的Path),若没有strCookiePath 参数,则使用web.config中 path属性的设置。

RedirectFromLoginPage方法生成生成身份验证票后,会调用FormsAuthentication.Encrypt 方法,将身份验证票加密为字符串,这个字符串将会是以.ASPXAUTH为名字的一个Cookie的值。这个Cookie的其它属性的生成:Domain,Path属性为确省值,Expires视createPersistentCookie参数而定,若是持久cookie,Expires设为50年以后过期;若是非持久cookie,Expires属性不设置。
生成身份验证Cookie后,将此Cookie加入到Response.Cookies中,等待发送到客户端。
最后RedirectFromLoginPage方法调用FormsAuthentication.GetRedirectUrl 方法获取到用户原先请求的页面,重定向到这个页面。

<forms>标签中的timeout和path,是提供了身份验证票写入到Cookie过期时间和默认路径。

timeout Cookies过期时间

 

访问受权

验证了身份,是要使用这个身份,根据不同的身份我们可以进行不同的操作,处理,最常见的就是对不同的身份进行不同的授权,Forms验证就提供这样的功能。Forms授权是基于目录的,可以针对某个目录来设置访问权限,比如,这些用户可以访问这个目录,那些用户不能访问这个目录。
同样,授权设置是在你要控制的那个目录下的web.config文件中来设置:

<authorization>
    <allow users="comma-separated list of users"
        roles="comma-separated list of roles"
        verbs="comma-separated list of verbs" />
     <deny users="comma-separated list of users"
        roles="comma-separated list of roles"
        verbs="comma-separated list of verbs" />
</authorization>

<allow>标签表示允许访问,其中的属性
1. users:一个逗号分隔的用户名列表,这些用户名已被授予对资源的访问权限。问号 (?) 允许匿名用户;星号 (*) 允许所有用户。
2. roles:一个逗号分隔的角色列表,这些角色已被授予对资源的访问权限。
3. verbs:一个逗号分隔的 HTTP 传输方法列表,这些 HTTP 传输方法已被授予对资源的访问权限。注册到 ASP.NET 的谓词为 GET、HEAD、POST 和 DEBUG。

<deny>标签表示不允许访问。其中的属性同上面的。

在运行时,授权模块迭代通过 <allow> 和 <deny> 标记,直到它找到适合特定用户的第一个访问规则。然后,它根据找到的第一项访问规则是 <allow> 还是 <deny> 规则来允许或拒绝对 URL 资源的访问。Machine.config 文件中的默认身份验证规则是 <allow users="*"/>,因此除非另行配置,否则在默认情况下会允许访问。

那么这些user 和roles又是如何得到的呢?下面看一下授权的详细过程:

1. 一旦一个用户访问这个网站,就行登录确认了身份,身份验证票的cookie也写到了客户端。之后,这个用户再次申请这个web的页面,身份验证票的cookie就会发送到服务端。在服务端,asp.net为每一个http请求都分配一个HttpApplication对象来处理这个请求,在HttpApplication.AuthenticateRequest事件后,安全模块已建立用户标识,就是此用户的身份在web端已经建立起来,这个身份完全是由客户端发送回来的身份验证票的cookie建立的。

2. 用户身份在HttpContext.User 属性中,在页面中可以通过Page.Context 来获取同这个页面相关的HttpContext对象。对于Forms验证,HttpContext.User属性是一个GenericPrincipal类型的对象,GenericPrincipal只有一个公开的属性Identity,有个私有的m_role属性,是string[]类型,存放此用户是属于哪些role的数组,还有一个公开的方法IsInRole(string role),来判断此用户是否属于某个角色。
由于身份验证票的cookie中根本没有提供role这个属性,就是说Forms身份验证票没有提供此用户的role信息,所以,对于Forms验证,在服务端得到的GenericPrincipal 用户对象的m_role属性永远是空的。
3. GenericPrincipal. Identity 属性是一个FormsIdentity类型的对象,这个对象有个Name属性,就是此用户的标示,访问授权就是将此属性做为user来进行授权验证的。FormsIdentity还有一个属性,就是Ticket属性,此属性是身份验证票FormsAuthenticationTicket类型,就是之前服务器写到客户端的身份验证票。
服务器在获取到身份验证票FormsAuthenticationTicket对象后,查看这个身份验证票是不是非持久的身份验证,是的话要根据web.config中timeout属性设置的有效期来更新这个身份验证票的cookie(为避免危及性能,在经过了超过一半的指定时间后更新该 Cookie。这可能导致精确性上的损失。持久性 Cookie 不超时。)
4. 在HttpApplication.ResolveRequestCache事件之前,asp.net开始取得用户请求的页面,建立HttpHandler控制点。这就意味着,在HttpApplication.ResolveRequestCache事件要对用户访问权限就行验证,看此用户或角色是否有权限访问这个页面,之后在这个请求的生命周期内再改变此用户的身份或角色就没有意义了。

以上是Forms验证的全过程,可以看出,这个Forms验证是基于用户的,没有为角色的验证提供直接支持。身份验证票FormsAuthenticationTicket 中的Name属性是用户标示,其实还有一个属性UserData,这个属性可以由应用程序来写入自定义的一些数据,我们可以利用这个字段来存放role的信息,从而达到基于角色验证的目的。

 

Forms身份验证基于角色的授权

在web.config的<authentication>的设置还是一样:

<authentication mode="forms">
    <forms name=".ASPXAUTH " loginUrl="/login.aspx" timeout="30" path= "/">
    </forms>
</authentication>

/login.aspx验证用户合法性页面中,在验证了用户的合法性后,还要有个取得此用户属于哪些role的过程,这个看各个应用的本身如何设计的了,一般是在数据库中会有个use_role表,可以从数据库中获得此用户属于哪些role,在此不深究如何去获取用户对应的role,最后肯定能够获得的此用户对应的所有的role用逗号分割的一个字符串。
在上面的非基于角色的方法中,我们用了FormsAuthentication.RedirectFromLoginPage 方法来完成生成身份验证票,写回客户端,浏览器重定向等一系列的动作。这个方法会用一些确省的设置来完成一系列的动作,在基于角色的验证中我们不能用这一个方法来实现,要分步的做,以便将一些定制的设置加进来:

1. 首先要根据用户标示,和用户属于的角色的字符串来创建身份验证票
public FormsAuthenticationTicket(
int version, //设为1
string name, //用户标示
DateTime issueDate, //Cookie 的发出时间, 设置为 DateTime.Now
DateTime expiration, //过期时间
bool isPersistent, //是否持久性(根据需要设置,若是设置为持久性,在发出cookie时,cookie的Expires设置一定要设置)
string userData, //这里用上面准备好的用逗号分割的role字符串
string cookiePath // 设为"/",这要同发出cookie的路径一致,因为刷新cookie要用这个路径
);

FormsAuthenticationTicket Ticket = new FormsAuthenticationTicket (1,"kent",DateTime.Now, DateTime.Now.AddMinutes(30), false,UserRoles,"/") ;

2. 生成身份验证票的Cookie
2.1 将身份验证票加密序列化成一个字符串
string HashTicket = FormsAuthentication.Encrypt (Ticket) ;
2.2 生成cookie
HttpCookie UserCookie = new HttpCookie(FormsAuthentication.FormsCookieName, HashTicket) ;
FormsAuthentication.FormsCookieName 是用来获取web.config中设置的身份验证cookie的名字,缺省为" .ASPXAUTH".
若身份验证票中的isPersistent属性设置为持久类,则这个cookie的Expires属性一定要设置,这样这个cookie才会被做为持久cookie保存到客户端的cookie文件中.
3. 将身份验证票Cookie输出到客户端
通过Response.Cookies.Add(UserCookie) 将身份验证票Cookie附加到输出的cookie集合中,发送到客户端.
4. 重定向到用户申请的初试页面.

验证部分代码(这部分代码是在login.aspx页面上点击了登录按钮事件处理代码):

ContractedBlock.gifExpandedBlockStart.gifCode
 1private void Buttonlogin_Click(object sender, System.EventArgs e)
 2ExpandedBlockStart.gifContractedBlock.gif{
 3     string user = TextBoxUser.Text; //读取用户名
 4     string password = TextBoxPassword.Text; //读取密码
 5     if(Confirm(user,password) == true//confirm方法用来验证用户合法性的
 6ExpandedSubBlockStart.gifContractedSubBlock.gif    {
 7         string userRoles = UserToRole(user); //调用UserToRole方法来获取role字符串
 8         FormsAuthenticationTicket Ticket = new FormsAuthenticationTicket (1,user,DateTime.Now,          DateTime.Now.AddMinutes(30), false,userRoles,"/") ; //建立身份验证票对象
 9         string HashTicket = FormsAuthentication.Encrypt (Ticket) ; //加密序列化验证票为字符串
10         HttpCookie UserCookie = new HttpCookie(FormsAuthentication.FormsCookieName, HashTicket) ; 
11//生成Cookie
12          Context.Response.Cookies.Add (UserCookie) ; //输出Cookie
13         Context.Response.Redirect (Context.Request["ReturnUrl"]) ; // 重定向到用户申请的初始页面
14     }

15    else
16ExpandedSubBlockStart.gifContractedSubBlock.gif    {
17        // 用户身份未被确认时的代码
18    }

19}

20//此方法用来验证用户合法性的
21private bool Confirm(string user,string password)
22ExpandedBlockStart.gifContractedBlock.gif{
23    //相应的代码
24}

25//此方法用来获得的用户对应的所有的role用逗号分割的一个字符串
26private string UserToRole(string user)
27ExpandedBlockStart.gifContractedBlock.gif{
28    //相应的代码
29}

30
31

基于角色访问授权

这里我们要做的是,将客户端保存的身份验证票中UserData中保存的表示角色的信息恢复到在服务端表示用户身份的GenericPrincipal对象中(记住,原来的验证过程中, GenericPrincipal对象只包含了用户信息,没有包含role信息)
一个Http请求的过程中,HttpApplication.AuthenticateRequest事件表示安全模块已建立用户标识,就是此用户的身份在web端已经建立起来, 在这个事件之后我们就可以获取用户身份信息了.
在HttpApplication.ResolveRequestCache事件之前,asp.net开始取得用户请求的页面,建立HttpHandler控制点,这时就已经要验证用户的权限了,所以恢复用户角色的工作只能在HttpApplication.AuthenticateRequest事件和HttpApplication.ResolveRequestCache事件之间的过程中做.
我们选择Application_AuthorizeRequest事件中做这个工作,可以在global.asax文件中处理HttpApplication的所有的事件,代码如下:

ContractedBlock.gifExpandedBlockStart.gifCode
 1protected void Application_AuthorizeRequest(object sender, System.EventArgs e)
 2ExpandedBlockStart.gifContractedBlock.gif{
 3    HttpApplication App = (HttpApplication) sender;
 4
 5    //获取本次Http请求相关的HttpContext对象
 6     HttpContext Ctx = App.Context ; 
 7
 8    //验证过的用户才进行role的处理
 9    if (Ctx.Request.IsAuthenticated == true
10ExpandedSubBlockStart.gifContractedSubBlock.gif    {
11        FormsIdentity Id = (FormsIdentity)Ctx.User.Identity ;
12        //取得身份验证票
13        FormsAuthenticationTicket Ticket = Id.Ticket ; 
14
15         //将身份验证票中的role数据转成字符串数组
16        string[] Roles = Ticket.UserData.Split (',') ;
17
18       //将原有的Identity加上角色信息新建一个GenericPrincipal表示当前用户,这样当前用户就拥有了role信息      
19        Ctx.User = new GenericPrincipal (Id, Roles) ;   
20   }

21}

22
23

访问者同时具有了user和role信息,就可以据此在web.config中用role来控制用户的访问权限了.

转载于:https://www.cnblogs.com/tangself/archive/2011/08/08/2130597.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/404997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我的SourceInsight配置(附图)

SourceInsight是个不错的工具&#xff0c;在开发过程中查看代码还是非常方便的&#xff0c;但是经常会出现这样一个问题&#xff1a;在sourceInsight中缩进整齐的代码&#xff0c;通过其他编辑器打开就不再对齐了&#xff0c;这看上去非常不爽。 在经过反复搜索、总结后&#…

[react] 你有用过React.Fragment吗?说说它有什么用途?

[react] 你有用过React.Fragment吗&#xff1f;说说它有什么用途 就是包裹几个同级元素&#xff0c;但是自身不会渲染在dom当中 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通…

linux tune2fs命令详解

From: http://blog.chinaunix.net/uid-7530389-id-2050094.html 一.简介&#xff1a; tune2fs是调整和查看ext2/ext3文件系统的文件系统参数&#xff0c;Windows下面如果出现意外断电死机情况&#xff0c;下次开机一般都会出现系统自检。Linux系统下面也有文件系统自检&#x…

[react] 说出几点你认为的React实践

[react] 说出几点你认为的React最佳实践 使用HOC实现组件复用完善测试用例Testing使用Typescript或者Flow对代码进行静态检测代码规范及格式化ES lint, Prettie个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家…

onvif概念及应用?

From: http://www.seeyoucctv.com/Security_camera/948.html 什么是ONVIF? 2008年5月&#xff0c;由安讯士(AXIS)联合博世(BOSCH)及索尼(SONY)公司三方宣布将携手共同成立一个国际开放型网络视频产品标准网络接口开发论坛&#xff0c;取名为ONVIF&#xff08;Open Network V…

WP7基础学习---第九讲

&#xff08;注&#xff1a;因为把第七讲和第八讲放在一起了&#xff0c;主要是对那两节的了解&#xff0c;简单应用&#xff0c;没太深究&#xff01;不过全景视图和枢轴视图真的效果很不错&#xff01;&#xff09; Express Blend工具&#xff1a; 本节主讲&#xff1a;对微软…

[react] create-react-app有什么好处?

[react] create-react-app有什么好处&#xff1f; The real tough part of react is webpack, by create-react-app we can just use the React out of the box. And its ready for both development and production deploy, cozy for new bees. We can also eject it for f…

ONVIF测试方法及工具

From: http://www.jiangyu.org/onvif-test-tool-and-method/ 设备是否支持ONVIF验证 1 ONVIF Test Tool安装 1.1PC安装环境要求&#xff1a;装有Microsoft .Net Framework 3.5或以上版本。 1.2安装源文件请见&#xff1a;ONVIF Conformance Test Tools.rar 2 ONVIF Conforma…

JavaScript窗体控制函数

2019独角兽企业重金招聘Python工程师标准>>> moveBy 从当前位置水平移动窗体x个像素&#xff0c;垂直移动窗体y个像素&#xff0c;x为负数&#xff0c;将向左移动窗体&#xff0c;y为负数&#xff0c;将向上移动窗体 moveTo 移动窗体左上角到相对于屏幕左上角的(x,y…

[react] React为什么不要直接修改state?如果想修改怎么做?

[react] React为什么不要直接修改state&#xff1f;如果想修改怎么做&#xff1f; 有时表现出异步,有时表现出同步 1&#xff1a;在合成事件和钩子函数当中是异步的&#xff0c;在原生事件和setTimeout当中是同步的 2&#xff1a;异步并不是说内部是由异步代码组成&#xff0c…

[MSSQL]COALESCE与ISNULL函数

同事的一道面试题: 如何将某表中的某字段以逗号分隔拼接起来 在给出答案前,先给出测试用数据,与之前的几篇一样: --DROP TABLE T CREATE TABLE T(GRP_A VARCHAR(20),GRP_B VARCHAR(20),GRP_C VARCHAR(20),VAL INT) INSERT INTO T(GRP_A,GRP_B,GRP_C,VAL) SELECT a1,b1,c1,10 un…

onvif规范 中文介绍

From: http://blog.csdn.net/ghostyu/article/details/8162193 什么是ONVIF ? ONVIF规范描述了网络视频的模型、接口、数据类型以及数据交互的模式。并复用了一些现有的标准&#xff0c;如WS系列标准等。 ONVIF规范的目标是实现一个网络视频框架协议&#xff0c;使不同厂商所…

[react] React的render中可以写{if else}这样的判断吗?

[react] React的render中可以写{if else}这样的判断吗&#xff1f; 不可以&#xff0c;可以用 三元运算符或者 与运算符操作 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前…

sunspot 查询语法

demand_text:12实际当中是字段demand,sunspot生成的时候会生成&#xff0c;demand_textsunspot内置的solr的版本http://127.0.0.1:8982/solr/admin/registry.jspSolr Specification Version: 1.4.0Solr Implementation Version: 1.4.0 833479 - grantingersoll - 2009-11-06 12…

gsoap使用总结

From: http://www.cnblogs.com/linxr/archive/2011/10/17/2215285.html >>用C实现WebService&#xff0c;gsoap是最好的选择了。近一个月都在折腾这个&#xff0c;做个总结吧&#xff0c;估计会写得比较长。因为其中碰到了不少问题&#xff0c;但最终都解决调了。 >…

[react] 使用React的memo和forwardRef包装的组件为什么提示children类型不对?

[react] 使用React的memo和forwardRef包装的组件为什么提示children类型不对&#xff1f; 过去使用Component、FC等类型定义组件时一般不需要我们定义props里children的类型&#xff0c;因为在上述类型里已经帮你默认加上了 { children?: ReactNode } 的定义。但是types/reac…

2011阿里巴巴程序设计公开赛 / 1002 Fruit Ninja

某神的代码&#xff1a; #include<stdio.h> #define max(x,y) (x)>(y)?(x):(y) #define min(x,y) (x)<(y)?(x):(y) const int inf0x7fffffff;struct node // Fruit {int adv;int x[11],y[11]; }Fruit[11];int Fruit_num,ans;//---- int judge( int x1…

绑定注意事项——数据源的属性

&#xff08;一&#xff09;属性的绑定总结&#xff08;以下属性均指“数据源的属性”&#xff09;&#xff1a; 1&#xff1a;属性的绑定&#xff08;单体属性和集合属性&#xff09;&#xff1a; 若要 将属性值或引用 的变化 通知给UI&#xff0c;则要求属性具有改变通知的功…

[react] 怎样将多个组件嵌入到一个组件中?

[react] 怎样将多个组件嵌入到一个组件中&#xff1f; import A from /* 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Bash脚本报错:“/bin/bash^M: bad interpreter: No such file or directory”

1、问题 github下载一个源码&#xff0c;运行install脚本时&#xff08;# ./myinstal_cp&#xff09;一直报错“/bin/bash^M: bad interpreter: No such file or directory”&#xff0c;如&#xff1a; -bash: ./myinstall_cp: /bin/bash^M: bad interpreter: No such file …