.NET2.0中Form验证的问题.
2006-09-15 06:23
260 查看
最近做一个SSO,使用Form认证方式,结果出了一个很让我郁闷的问题.先描述下问题:
用户登陆时,可以选择是否保存cookie,以便以后直接访问,如果选择否,则在不活动指定时间后,将自动注销.
Web.config中的设置如下:
<authentication mode="Forms">
<forms name=".SFCMS" protection="All" timeout="5" loginUrl="login.aspx" slidingExpiration="false" />
</authentication>
这里只解释一下timeout参数,表示如果建立的是非持久性cookie,在不活动多长时间后,将需要重新验证,如果建立的是持久性cookie,那么该参数无效.
登陆时的建立验证cookie的代码如下:
HttpCookie authCookie = FormsAuthentication.GetAuthCookie("wiseman", true);
uthCookie.Expires = DateTime.Now.Add(TimeSpan.FromHours(1));
HttpContext.Current.Response.Cookies.Add(authCookie);
这里需要重点注意的就是FormsAuthentication.GetAuthCookie (string userName,bool createPersistentCookie)函数,在这里两个参数分别表示验证的用户名和是否持久保存cookie,上面我们的代码设置为true,表示将持久保持该cookie,过期时间是一个小时后.
但实际上,效果完全不是如此,用Request.IsAuthenticated你会发现,在很短的时间内,更确切的说是在5分钟以后,也就是我们在config中配置的timeout值,它的值就会变成false.
这意味着,我们在建立验证cookie时设置的过期时间没有起到效果,那么是cookie失效了吗?答案是否定的.在验证失败之后,我们依然可以取得cookie的值,这表示,在客户端建立的cookie没有问题,那么便是服务端的验证票据出了问题.
先来看看.net2.0中GetAuthCookie的代码.
private static HttpCookie GetAuthCookie(string userName, bool createPersistentCookie, string strCookiePath, bool hexEncodedTicket)
问题果然出在这里:
FormsAuthenticationTicket ticket1 = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddMinutes((double) FormsAuthentication._Timeout), createPersistentCookie, string.Empty, strCookiePath);
这句代码表明,建立的验证票据过期时间只与web.config有关,即使我们在获得cookie后,修改其过期时间,也无法对票据的过期产生影响,这样产生的结果就是,客户端的cookie存在,但是服务器端的验证票据已经失效,最终,验证失败.
这里还需要提一下的是createPersistentCookie这个参数,当它为true时,并不表示票据将持久存在,而是表示可以跨越浏览器存在,简单点说就是即使你关了浏览器,只要过期时间不到,验证就依然是有效的.
实际上,很多人和我一样,在.net1.1时就使用了form认证,也使用过GetAuthCookie函数,处理方式也与我上面写的一样,并没出过什么问题,在CommunityServer2.0中,也是这么处理.那在.NET2.0中为什么不行呢?
原因其实很简单,因为在framework中,GetAuthCookie 函数1.1和2.0是不一样的,更准确的说是从2.0RTM版开始,GetAuthCookie函数进行了修改.下面给出.net1.1的GetAuthCookie函数代码:
public static HttpCookie GetAuthCookie(string userName, bool createPersistentCookie, string strCookiePath)
基本没什么区别,除了这句:
FormsAuthenticationTicket ticket1 = new FormsAuthenticationTicket(1, userName, DateTime.Now, createPersistentCookie ? DateTime.Now.AddYears(50) : DateTime.Now.AddMinutes((double) FormsAuthentication._Timeout), createPersistentCookie, "", strCookiePath);
这里在创建票据时,如果是创建持久性票据,过期时间设定为了50年,那么在50年的范围内,设定的cookie过期时间将影响是否验证成功,所以,如果最上面的代码在.NET1.1中运行的话,则是完全没有问题的.
上面说到CommunityServer2.0有这个问题,实际上CS2.0是基于.NET1.1的系统,所以在1.1环境下没有问题的;虽然它也提供了.NET2.0的solution,但是里面的代码并没有做相应的变动.
这就是为什么网上很多朋友在部署CS2.0时说无法保持自动登陆,而有许多朋友则表示没有问题.部署在1.1环境下的没有问题,而部署在2.0环境下的则会出现上述问题.
在MSDN2005中,并没有对GetAuthCookie函数做过多的说明,这也是造成许多程序员误解的原因,甚至被当做bug被提交.http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=102143
单从功能上来说,我不知道微软的这次改变有什么意义,直接导致的结果是我无法再使用GetAuthCookie,在不修改config文件的前提下,我将无法保持我的form验证能长期存在,唯一的解决方案就是把config文件中的timeout值设大.
据MS宣称这是出于安全的考虑,具体的原因还是不清楚,如果有哪位朋友知道,不妨帖出来让大家看下.
最后再给个问题的解决方案,其实算不上什么解决方案,也就是不用GetAuthCookie函数了,自己处理,如下:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, "wiseman",
DateTime.Now, DateTime.Now.AddHours(1), true, "", FormsAuthentication.FormsCookiePath);
string ticketEncrypted = FormsAuthentication.Encrypt(ticket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, ticketEncrypted);
authCookie.HttpOnly = true;
authCookie.Path = FormsAuthentication.FormsCookiePath;
authCookie.Secure = FormsAuthentication.RequireSSL;
authCookie.Expires = ticket.Expiration;
HttpContext.Current.Response.Cookies.Add(authCookie);
手动建立票据和cookie,自己设定票据的过期时间,测试通过.
用户登陆时,可以选择是否保存cookie,以便以后直接访问,如果选择否,则在不活动指定时间后,将自动注销.
Web.config中的设置如下:
<authentication mode="Forms">
<forms name=".SFCMS" protection="All" timeout="5" loginUrl="login.aspx" slidingExpiration="false" />
</authentication>
这里只解释一下timeout参数,表示如果建立的是非持久性cookie,在不活动多长时间后,将需要重新验证,如果建立的是持久性cookie,那么该参数无效.
登陆时的建立验证cookie的代码如下:
HttpCookie authCookie = FormsAuthentication.GetAuthCookie("wiseman", true);
uthCookie.Expires = DateTime.Now.Add(TimeSpan.FromHours(1));
HttpContext.Current.Response.Cookies.Add(authCookie);
这里需要重点注意的就是FormsAuthentication.GetAuthCookie (string userName,bool createPersistentCookie)函数,在这里两个参数分别表示验证的用户名和是否持久保存cookie,上面我们的代码设置为true,表示将持久保持该cookie,过期时间是一个小时后.
但实际上,效果完全不是如此,用Request.IsAuthenticated你会发现,在很短的时间内,更确切的说是在5分钟以后,也就是我们在config中配置的timeout值,它的值就会变成false.
这意味着,我们在建立验证cookie时设置的过期时间没有起到效果,那么是cookie失效了吗?答案是否定的.在验证失败之后,我们依然可以取得cookie的值,这表示,在客户端建立的cookie没有问题,那么便是服务端的验证票据出了问题.
先来看看.net2.0中GetAuthCookie的代码.
private static HttpCookie GetAuthCookie(string userName, bool createPersistentCookie, string strCookiePath, bool hexEncodedTicket)
问题果然出在这里:
FormsAuthenticationTicket ticket1 = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddMinutes((double) FormsAuthentication._Timeout), createPersistentCookie, string.Empty, strCookiePath);
这句代码表明,建立的验证票据过期时间只与web.config有关,即使我们在获得cookie后,修改其过期时间,也无法对票据的过期产生影响,这样产生的结果就是,客户端的cookie存在,但是服务器端的验证票据已经失效,最终,验证失败.
这里还需要提一下的是createPersistentCookie这个参数,当它为true时,并不表示票据将持久存在,而是表示可以跨越浏览器存在,简单点说就是即使你关了浏览器,只要过期时间不到,验证就依然是有效的.
实际上,很多人和我一样,在.net1.1时就使用了form认证,也使用过GetAuthCookie函数,处理方式也与我上面写的一样,并没出过什么问题,在CommunityServer2.0中,也是这么处理.那在.NET2.0中为什么不行呢?
原因其实很简单,因为在framework中,GetAuthCookie 函数1.1和2.0是不一样的,更准确的说是从2.0RTM版开始,GetAuthCookie函数进行了修改.下面给出.net1.1的GetAuthCookie函数代码:
public static HttpCookie GetAuthCookie(string userName, bool createPersistentCookie, string strCookiePath)
基本没什么区别,除了这句:
FormsAuthenticationTicket ticket1 = new FormsAuthenticationTicket(1, userName, DateTime.Now, createPersistentCookie ? DateTime.Now.AddYears(50) : DateTime.Now.AddMinutes((double) FormsAuthentication._Timeout), createPersistentCookie, "", strCookiePath);
这里在创建票据时,如果是创建持久性票据,过期时间设定为了50年,那么在50年的范围内,设定的cookie过期时间将影响是否验证成功,所以,如果最上面的代码在.NET1.1中运行的话,则是完全没有问题的.
上面说到CommunityServer2.0有这个问题,实际上CS2.0是基于.NET1.1的系统,所以在1.1环境下没有问题的;虽然它也提供了.NET2.0的solution,但是里面的代码并没有做相应的变动.
这就是为什么网上很多朋友在部署CS2.0时说无法保持自动登陆,而有许多朋友则表示没有问题.部署在1.1环境下的没有问题,而部署在2.0环境下的则会出现上述问题.
在MSDN2005中,并没有对GetAuthCookie函数做过多的说明,这也是造成许多程序员误解的原因,甚至被当做bug被提交.http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=102143
单从功能上来说,我不知道微软的这次改变有什么意义,直接导致的结果是我无法再使用GetAuthCookie,在不修改config文件的前提下,我将无法保持我的form验证能长期存在,唯一的解决方案就是把config文件中的timeout值设大.
据MS宣称这是出于安全的考虑,具体的原因还是不清楚,如果有哪位朋友知道,不妨帖出来让大家看下.
最后再给个问题的解决方案,其实算不上什么解决方案,也就是不用GetAuthCookie函数了,自己处理,如下:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, "wiseman",
DateTime.Now, DateTime.Now.AddHours(1), true, "", FormsAuthentication.FormsCookiePath);
string ticketEncrypted = FormsAuthentication.Encrypt(ticket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, ticketEncrypted);
authCookie.HttpOnly = true;
authCookie.Path = FormsAuthentication.FormsCookiePath;
authCookie.Secure = FormsAuthentication.RequireSSL;
authCookie.Expires = ticket.Expiration;
HttpContext.Current.Response.Cookies.Add(authCookie);
手动建立票据和cookie,自己设定票据的过期时间,测试通过.
相关文章推荐
- .NET2.0中Form验证的问题.
- .net 2.0 remoting 中 TCP Channel 用户认证探讨 (转) 可以作为问题的引子,目前内容无法验证是正确的
- [导入]经验:使用.net 2.0中的TransactionScope碰到的问题
- 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十四║ Vuex + JWT 实现授权验证登陆
- jQuery formValidator表单验证插件常见有关问题
- form表单提交,上传文件以及提交前验证的问题。
- 从 .net 1.1 升级到 2.0过程中遇到的问题及解决方法
- VS2010安装部署成.NET 2.0过程的几个问题(转)
- DNN单独模块开发.net 2.0 到.net 3.5的问题
- 在asp.net mvc2.0 modell字段中包含对象的验证问题
- Moss中Form验证中"找不到匹配项"问题的处理
- VS2010安装部署成.NET 2.0过程的几个问题
- .NET 2.0 Configuration配置文件的保存问题
- Vue2.0+ElementUI简单form表单验证
- .NET 2.0中SmtpClient的乱码问题
- Laravel5.2 关于$errors变量的问题 form 表单验证
- 从Framework2.0升级到4.0后document.form1 报错问题解决
- 将使用AJAX的DNN模块部署到.net 2.0站点上的问题
- 终于解决了 .NET 2.0 的URL解码问题
- 用Delphi7 调用.NET 2.0的WebService 所要注意的问题