深入分析自定义表单验证与Cookies

深入分析自定义表单验证与Cookies
[Key words:Form,Security, FormsAuthentication, FormsAuthenticationTicket,cookies]

在ASP.net项目中,身份验证为我们提供了很多方便,而做为中小型的项目,一般都采用了表单验证。关于ASP.net里的表单验证,可以MSDN里的相关文章里找到很详细的说明。而且单单只是表单认证也是很简单的,这里就不去讨论它了。这里我想主要分析一下自己定义认证票据及Cookies之间的关系。
先给一个自己定义票据的例子:

        public virtual  void Login(bool i_autoLogin)
        
{
            
string m_userData    = this.m_userID.ToString()+","+this.m_loginName+","+this.m_userType.ToString();
            FormsAuthenticationTicket ticket 
= new FormsAuthenticationTicket(
                
1,
                
"WebbUser",
                System.DateTime.Now,
                System.DateTime.Now.AddDays(
30),
                i_autoLogin,
                m_userData,
                
"");
            
string encTicket = FormsAuthentication.Encrypt(ticket);
            HttpContext.Current.Response.Cookies.Set(
new HttpCookie("WebbUser", encTicket));
        }

其中的m_userData可是自己定义的任何字符串,最后通过FormsAuthentication.Encrypt(ticket)加密然后添加到客户端。关于FormsAuthenticationTicket,在MSDN里也有相关说明。而我想说的是它的最后一个参数:MSDN里明确表示,要用"/",而通过多次测试,发现用其它任何有意义的字符串都可以,但不管你加了什么字符后,你所建立的表单票据都成了临时的了(多次测试,几乎让我疯掉了),而这里的时间参数根本无效即cookies建立在浏览器内存里,关闭浏览器后就无效,也就根本起为不了自动登录的功能。反到是把最后一个参数设定为空字符串,可以建立永久的Cookies。这里,我用了空串,让它建立永久的Cookies。

而最后我也用了Set Cookies而不是Add,这是有道理的。就算是第一次建立Cookies也可以建立成功,而用Add则会添加新的Cookies.其实我也不大明白这两者的区别。
取回自己定义的票据数据:当然,最后还要把取回来的数据设定成可用的格式。

        protected void GetDataFromCookie()
        
{
            
if(User.Identity.IsAuthenticated)
            
{
                
string m_userData;
                FormsIdentity id 
= (FormsIdentity)User.Identity;
                FormsAuthenticationTicket ticket 
= id.Ticket;
                m_userData        
= ticket.UserData;
                
if(m_userData!=null)
                
{
                    SetUserData(m_userData);
                }

            }

        }


看上去这些很完美了,然而让我发疯的是它的注销。因为这里自己定义了票据,而这里的票据又是以Cookies添加在客户端的,所以用简单的:FormsAuthentication.SignOut();根本无效。于是简单的方法是想到自己处理Cookies,而处理Cookies就让我郁闷了。先看看Trace的结果:

Cookies Collection

Name Value Size
WebbUser 28B93F4A0C8791830157006500620062005500730065007200000042C9ABA1550CC601014249109AE823C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
ASP.NET_SessionId fvfyp4b2fchyvwy1pwowt5ur 42
WebbUser 28B93F4A0C8791830157006500620062005500730065007200000042C9ABA1550CC601014249109AE823C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
14
我百思不得其解的是:为什么会有两个WebbUser?而且值完全一样?
做一个小的测试:

        private void Button1_Click(object sender, System.EventArgs e)
        
{
            HttpCookie m_cookie 
= Request.Cookies["WebbUser"];
            m_cookie.Value        
= "Changed";
            Response.Cookies.Set(m_cookie);
        }

其后我得到的结果是:

Cookies Collection

Name Value Size
WebbUser 28B93F4A0C8791830157006500620062005500730065007200000042C9ABA1550CC601014249109AE823C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
ASP.NET_SessionId h1rdcxu21s4awxmupsiw5znc 42
WebbUser Changed 16
这里明显的只改变了一个Cookies,而且说明这里确实有两个Cookies在“系统”里(谁知道在哪里呀)。而这里改变了其实的一个。关闭浏览器,再直接打开,然后得到:

Cookies Collection

Name Value Size
WebbUser Changed 16
ASP.NET_SessionId 55icvo452ltsid454jtuklf0 42

猜测以下结论:
1、一个Cookie是在浏览器里,而另一个则是在Cookie文件里。
2、修改时,只修改了文件里的那一个,而浏览器里的没有变。但表单验证以文件为准,所以当我自己修改Cookies后,表单验证是失效了的。

再次登录,得到以下内容:

Cookies Collection

Name Value Size
WebbUser Changed 16
ASP.NET_SessionId 4koyqb45dqm1qm551eahe245 42
WebbUser 00E5C94AF9B385BA0157006500620062005500730065007200000064B91EC4E40CC60101643983BC7724C601320031002C00570075002E0043006F0075006E007400720079002C0043006C00690065006E00740000000000 185

这说明登录是失败的,因为根据上面的猜测,它只是在浏览器里建立一个临时的认证,而ASP.net要以文件认证,所以登录后,又被导入到登录页面。这让我很郁闷,因为我我的登录确实是重新设置了Cookies的。下面的测试更让人郁闷:

        private void Button4_Click(object sender, System.EventArgs e)
        
{
            HttpCookieCollection m_cookies    
= Request.Cookies;
            
for(int i=0;i<m_cookies.Count;i++)
            
{
                m_cookies[i].Value        
= DateTime.Now.ToString();
                m_cookies[i].Expires    
= DateTime.Now.AddMinutes(-1);
                Response.Cookies.Set(m_cookies[i]);
            }

        }

结果是:

Cookies Collection

Name Value Size
WebbUser Changed 16
ASP.NET_SessionId 4koyqb45dqm1qm551eahe245 42
WebbUser 00E5C94AF9B385BA0157006500620062005500730065007200000064B91EC4E40CC60101643983BC7724C601320031002C00570075002E0043006F0075006E007400720079002C0043006C00690065006E00740000000000 185
WebbUser 12/30/2005 10:06:14 AM 31
ASP.NET_SessionId 12/30/2005 10:06:14 AM 40
显然,我修改了两个Cookies,根据ASP.NET_SessionId是在浏览器里的依据,可以猜测,所做的修改都只在浏览器里。而这里仍然保留了另一个正确的Cookie在浏览器里,也就是说,上面的Set方法完全无效,而只是添加了临时的Cookies.不解。。。。。。而接下来的问题是,我修改了论证后的Cookies,如何再次可以登录系统呢(当然,用IE选项删除所有Cookies是一最终解决方法)?
修改登录代码:

        public virtual  void Login(bool i_autoLogin)
        
{
            
string m_userData    = this.m_userID.ToString()+","+this.m_loginName+","+this.m_userType.ToString();
            FormsAuthenticationTicket ticket 
= new FormsAuthenticationTicket(
                
1,
                
"WebbUser",
                System.DateTime.Now,
                System.DateTime.Now.AddDays(
30),
                i_autoLogin,
                m_userData,
                
"");
            
string encTicket = FormsAuthentication.Encrypt(ticket);
            HttpCookie m_cookie    
= HttpContext.Current.Request.Cookies.Get("WebbUser");
            WaveHelper.TraceMsg(m_cookie.Value);
            m_cookie.Value        
= encTicket;
            
//HttpContext.Current.Response.Cookies.Set(new HttpCookie("WebbUser", encTicket));
            HttpContext.Current.Response.Cookies.Set(m_cookie);
        }

测试输出:12/30/2005 10:14:32 AM Changed
说明取得了文件Cooikes里的正确值,但设置却只是临时,这是什么道理呢?为什么第一次登录的时候可以呢?而且第一次修改为"Changed"的时候如此的理所当然,以致于可以想到可以把它设定为任何想要的内容,可惜其后的所有设定都失败。
更为有意思的事,登录后,刷新页面可以得到页面里不断的添加新的Cooikes,而最多只有三个。不断刷新页面,得到下面的结果:

1
Cookies Collection

Name Value Size
WebbUser E7CCE30B0614E23101570065006200620055007300650072000000BC1DF89AEB0CC60101BC9D5C937E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
ASP.NET_SessionId 1ck3eunw3fkiiuulbxvvrg45 42
WebbUser CFCF23BA7B3631F801570065006200620055007300650072000000584EDA96EB0CC6010158CE3E8F7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
WebbUser D0E2E460A26850DC015700650062006200550073006500720000005625A99DEB0CC6010156A50D967E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
2

Cookies Collection

Name Value Size
WebbUser D0E2E460A26850DC015700650062006200550073006500720000005625A99DEB0CC6010156A50D967E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
ASP.NET_SessionId 1ck3eunw3fkiiuulbxvvrg45 42
WebbUser CFCF23BA7B3631F801570065006200620055007300650072000000584EDA96EB0CC6010158CE3E8F7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
WebbUser 525BE5D26ED817F0015700650062006200550073006500720000001C9BB3ACEB0CC601011C1B18A57E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173

3
Cookies Collection

Name Value Size
WebbUser 525BE5D26ED817F0015700650062006200550073006500720000001C9BB3ACEB0CC601011C1B18A57E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
ASP.NET_SessionId 1ck3eunw3fkiiuulbxvvrg45 42
WebbUser CFCF23BA7B3631F801570065006200620055007300650072000000584EDA96EB0CC6010158CE3E8F7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
WebbUser C13C21C845D22DDE015700650062006200550073006500720000001CA9DAB3EB0CC601011C293FAC7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
4

Cookies Collection

Name Value Size
WebbUser C13C21C845D22DDE015700650062006200550073006500720000001CA9DAB3EB0CC601011C293FAC7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
ASP.NET_SessionId 1ck3eunw3fkiiuulbxvvrg45 42
WebbUser CFCF23BA7B3631F801570065006200620055007300650072000000584EDA96EB0CC6010158CE3E8F7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
WebbUser 1E7280709500E99E015700650062006200550073006500720000006A377CC2EB0CC601016AB7E0BA7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
显然,每次登录后得到的认证加密数据是不一样的,但我们可以看到第二个WebbUser一直没有变!为什么?而其它两个则是不断的由新的替换旧的。

我已经没有办法区分它们的关系了,还想去猜测一下,哪几个在内存里,哪一个或者哪几个在文件里?关闭浏览器,再打开,得到下面的结果?两个?昏。。。。。

Cookies Collection

Name Value Size
WebbUser 1E7280709500E99E015700650062006200550073006500720000006A377CC2EB0CC601016AB7E0BA7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
WebbUser 1E7280709500E99E015700650062006200550073006500720000006A377CC2EB0CC601016AB7E0BA7E24C60131002C007700650062006200610064006D0069006E002C00410064006D0069006E0000000000 173
ASP.NET_SessionId 1nt5n0uwvcavxfev3xgolh55 42

14

修改后刷新,得到下面的结果:

Cookies Collection

Name Value Size
WebbUser 12/30/2005 10:55:57 AM 31
ASP.NET_SessionId fgc1pb45r3y4qx55a2dke2y3 42
WebbUser 12/30/2005 10:56:06 AM 31
WebbUser 12/30/2005 10:56:13 AM 31

几乎疯掉了,如果不能修改它的值,为什么可以在第一次修改,而其后所有的修改都失败,包括过期时间的修改。没道理。。。。。。。。。。而它对认证还起作用,也是没道理的。。。。。

我只能给出以下结论与解决方法了:1、这是ASP.net及浏览器间存在的问题。2、放弃使用自定义票据的表单验证。因为我并不想让所有出了问题的用户都去删除Cookies.

最后通过几次测试发现,可以用Add方法覆盖式的修改Cookies,但不管怎样,这里的Cookies与自己定义的表单验证是有问题的。最后为了安全起见,在项目里又添加了一个一般Cookies做为后备,这样在验证退出或者验证失败的时候,还可以用一般的Cookies再验证一次,然后强行退出要求用户登录。当然,如果登录不成功的话,那就只有手动删除Cookies了。伤心呀。。。。。。。。。。

================================
  /\_/\                        
 (=^o^=)  Wu.Country@侠缘      
 (~)@(~)  一辈子,用心做一件事!
--------------------------------
  学而不思则罔,思而不学则怠!  
================================
原文地址:https://www.cnblogs.com/WuCountry/p/307577.html