网站开发中用户验证一般采用Asp.Net的Forms验证,验证票据存储到Cookie的方式。
Session方式是将验证信息存储在内存中,如果你使用的虚拟主机给你分配很小的内存,实际上都是如此,那么session就会很快过期,要求你重新登录,如果用户正在填写信息,被要求重新登录,那愤怒的感觉可想而知。
cookie是存储在用户的客户端的。但是也会碰到失效的问题,下面一一来了解。
在ASP.NET Forms验证中,通常我们会使用ASP.NET自带的Login控件来进行验证。同时,在web.config文件中,我们所有的Forms设置都设为默认。现在,问题就来了。
1.为什么我明明点了"Remember me",而大概半个小时后,我又Log out了?
2.为什么我明明设置了timeout为无限期 e.g. 400000,为什么一两天之后我又Log out了呢?
这是Forms验证中遇到的比较多的问题。下面,我就这两个问题做一个详细的解释:对于问题一,首先我要阐明ticket和cookie的区别。 cookie是一个容器,用来存放东西,它是保存在客户端的。而ticket是具体的数据,用来表示具体的验证信息,它是放在cookie这个容器中的。 因而,在我们验证的过程中,以下事情发生了。首先,ticket被创造了,里面包含着用户名等信息,同时它有一个过期时间。
然后,cookie被创造了,它同样也有一个过期时间。最后,将ticket保存在cookie中,并将此cookie发送到client的浏览器中。读 到这里,我想问题已经很明白了,用户的Log out就是因为时间过期的问题。但具体是谁的时间过期了呢?在我们ASP.NET web.config的设置中,timeout是cookie的过期时间(注意,默认是30分钟),而ticket的过期时间是无限的,因为我们选 了"Remember me".这就是为什么虽然我点了"Remember me"。
但在30分钟左右后,我仍然被Log out了,因为我们并没有设置cookie的timeout.ticket和cookie,只要其中之一不是永远不过期,我们都无法实现永不过期。
当我们解决了问题一后(假如手动设置timeout="4000000"),我们又遇到了问题二。这又是什么原因呢?这得从ticket的加密解密机制说 起。ASP.NET会使用一个machinekey来对cookie进行加密,这个machinekey默认是在application启动时随机生成 的。然后,ASP.NET会使用同一个machinekey进行cookie进行解密。正式因为这个key是application启动时随机生成的才导 致了问题二。试想,如果application recycle(重启)了怎么办?
ASP.NET会生成另一个key进行解密,以前的cookie将不再有效,这就是问题二的原因了。知道了这个,解决第二个问题的办法就很简单了, 手动设置一个特定的key.如:<machineKey validationKey="88CB6CA6CF403C5FBB41C2F62BB7FCFCA05DE7BE" decryptionKey="B8A7CF3816C57176" validation="SHA1" />
{
private IUserService userService;
public IUserService UserService
{
set { userService = value; }
}
public void MarkCurrentUser(User user, bool isPersistent)
{
string mUserData = string.Format("{0};{1};{2}", user.Account, user.UserName, user.EmployeeNO);
SaveToCookies(user.Account, mUserData, isPersistent);
}
public User CurrentUser(bool fullData)
{
User member = GetFromCookies<User>();
if (fullData && member != null && !string.IsNullOrEmpty(member.Account))
{
return userService.GetObjectById(null, member.Account);
}
return member;
}
private static T GetFromCookies<T>() where T : class
{
if (HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated
&& (HttpContext.Current.User.Identity is FormsIdentity))
{
HttpCookie myCookie = HttpContext.Current.Request.Cookies["ud"];
if (myCookie != null && !string.IsNullOrEmpty(myCookie.Value))
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(myCookie.Value);
if (ticket != null)
{
string[] userInfoArray = ticket.UserData.Split(';');
//UserData format like as "loginName;password;role1,role2,role3..."
if (userInfoArray.Length == 3 && typeof(T).Name == "User")
{
User member = new User();
member.Account = userInfoArray[0];
member.UserName = userInfoArray[1];
member.EmployeeNO = userInfoArray[2];
return member as T;
}
}
}
}
return default(T);
}
private static void SaveToCookies(string name, string mUserData, bool isPersistent)
{
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
name,
DateTime.Now,
DateTime.Now.AddDays(1),
isPersistent,
mUserData);
string hashTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie("ud", hashTicket);
if (HttpContext.Current.Response.Cookies["ud"] != null)
{
HttpContext.Current.Response.Cookies["ud"].Expires = DateTime.Now.AddDays(-1d);
}
HttpContext.Current.Response.Cookies.Add(cookie);
}
}