在我推出0804版后不久就有人反映修改密码后无法登录,很抱歉一直没有看这个bug,今天仔细检查了一下代码,很快就找到了原因所在:
asp.net forums的密码加密是通过salt和真实密码混合加密得出的(salt称为盐,是一串随机字符串,每个用户的salt值是不一样的,这样不同用户即使密码相同,加密出来的密码也是不一样的),所以每次用户登录前,必须先获取他的salt值,以用来和他输入的密码混合加密,将加密后的字符串和数据库中存储的密码相比较来验证密码是否正确。
为了避免过于频繁的操作数据库,asp.net forums中大量的使用了缓存技术,其中有一个Cache就是专门用来存储用户信息的,所有查询过的用户信息,都存储在该Cache中的HashTable中,如果Cache的HashTable中不存在所要获取的用户信息,则从数据库中读取该用户信息,并Cache之,否则直接从Cache中获取,无需再读一次数据库。
在修改密码时,会创建一个新的salt值,和新密码重新加密生成新的salt和密码存储到数据库中。对于asp.net forums2.0 Gold ,当用户重新登录时,验证所使用的salt值还是从缓存中读取的就的salt值,这样自然会导致验证出错!所以解决方法就是每次修改密码/资料的同时,将Cache中的资料同时更新,或者将用户资料直接从Cach中清除!
在这里,我所用的解决方法就是在成功修改密码后清除Cache,部分代码如下:
/// <summary>
/// 清除缓存中指定用户的信息
/// </summary>
/// <param name="user"></param>
public static void ClearUserCache(User user)
{
ForumContext forumContext = ForumContext.Current;
string cacheKey = "UserLookupTable";
if (HttpRuntime.Cache[cacheKey] == null)
return;
// 所有缓存的用户都存储在缓存的一个HashTable中
Hashtable userLookupTable = (Hashtable) HttpRuntime.Cache[cacheKey];
string userKey;
// 移除指定用户的缓存
userKey = "User-" + user.UserID;
if (forumContext.Context.Items[userKey] != null)
forumContext.Context.Items.Remove(userKey);
if (userLookupTable.ContainsKey(userKey))
userLookupTable.Remove(userKey);
userKey = "User-" + user.Username;
if (forumContext.Context.Items[userKey] != null)
forumContext.Context.Items.Remove(userKey);
if (userLookupTable.ContainsKey(userKey))
userLookupTable.Remove(userKey);
}
/// 清除缓存中指定用户的信息
/// </summary>
/// <param name="user"></param>
public static void ClearUserCache(User user)
{
ForumContext forumContext = ForumContext.Current;
string cacheKey = "UserLookupTable";
if (HttpRuntime.Cache[cacheKey] == null)
return;
// 所有缓存的用户都存储在缓存的一个HashTable中
Hashtable userLookupTable = (Hashtable) HttpRuntime.Cache[cacheKey];
string userKey;
// 移除指定用户的缓存
userKey = "User-" + user.UserID;
if (forumContext.Context.Items[userKey] != null)
forumContext.Context.Items.Remove(userKey);
if (userLookupTable.ContainsKey(userKey))
userLookupTable.Remove(userKey);
userKey = "User-" + user.Username;
if (forumContext.Context.Items[userKey] != null)
forumContext.Context.Items.Remove(userKey);
if (userLookupTable.ContainsKey(userKey))
userLookupTable.Remove(userKey);
}