網站開發中用戶驗證一般採用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);
}
}