搜集整理了一篇關(guān)于.net驗(yàn)證方式的文章,大家看看。 此前我介紹了使用數(shù)據(jù)庫實(shí)現(xiàn)的提交驗(yàn)證方案,一些朋友懷疑其效率不佳,認(rèn)為Session是更好的方案。
的確使用Session也不會消耗太多內(nèi)存,而且如今內(nèi)存白菜價(jià),最不濟(jì)就隨手買個2G的插上也就夠了,所以我將在此寫下Session版的實(shí)現(xiàn)提要,其余細(xì)節(jié)參考前篇。 實(shí)現(xiàn)方案簡述: 在Session中存儲一個哈希表用以記錄該用戶的每一條驗(yàn)證信息,哈希表的鍵為驗(yàn)證信息的過期時間,值為驗(yàn)證碼的明文。 過期時間使用ViewState存儲,以發(fā)給客戶端,并在提交時獲取,以讀取對應(yīng)的驗(yàn)證碼明文。 傳給驗(yàn)證碼生成頁面的ID參數(shù)是經(jīng)ToFileTime()方法轉(zhuǎn)換的過期時間,驗(yàn)證碼生成頁獲取到此參數(shù)后進(jìn)行逆轉(zhuǎn)換,再讀取對應(yīng)的驗(yàn)證碼明文以生成顯示。 代碼講解: 先建立一個靜態(tài)類,名為“提交驗(yàn)證”,將用于存儲驗(yàn)證信息的Session變量封裝為一個屬性:
/// <summary>
/// 驗(yàn)證信息表
/// </summary>
static Hashtable 驗(yàn)證信息
{
get
{
return Core.函數(shù)庫.網(wǎng)絡(luò).Session["驗(yàn)證信息"] as Hashtable;
}
set
{
Core.函數(shù)庫.網(wǎng)絡(luò).Session["驗(yàn)證信息"] = value;
}
}
清理方法,用于將過期的數(shù)據(jù)清除: /// <summary> /// 清理所有過期的驗(yàn)證信息
/// </summary> public static void 清理()
{
if (驗(yàn)證信息 == null || 驗(yàn)證信息.Count < 5) return;
foreach (DictionaryEntry f in (Hashtable)驗(yàn)證信息.Clone())
{ if ((DateTime)f.Key < DateTime.Now) 驗(yàn)證信息.Remove(f);
}
}
小于5條驗(yàn)證信息則忽略。
克隆一個驗(yàn)證信息表供foreach使用,如果使用原表循環(huán)的話,直接移除內(nèi)容會改變表長度,從而引發(fā)異常。
添加方法:
/// <summary>
/// 添加一個新的驗(yàn)證信息。
/// </summary>
/// <param name="驗(yàn)證碼">要保存的驗(yàn)證碼</param>
/// <param name="過期時間差值">用于計(jì)算過期時間,單位為分鐘</param>
/// <returns>過期時間戳</returns>
public static DateTime 添加(string 驗(yàn)證碼, byte 過期時間差值)
{
清理();
var 過期時間 = DateTime.Now.AddMinutes(過期時間差值);
if (驗(yàn)證信息 == null) 驗(yàn)證信息 = new Hashtable();
驗(yàn)證信息.Add(過期時間, 驗(yàn)證碼);
return 過期時間;
}
在添加前進(jìn)行過期信息清理工作。 獲取、驗(yàn)證、移除方法: /// <summary> /// 根據(jù)過期時間戳獲取對應(yīng)的驗(yàn)證碼 /// </summary> /// <param name="過期時間戳">驗(yàn)證信息過期時間戳</param> /// <returns>驗(yàn)證碼明文</returns> public static string 獲取(DateTime 過期時間戳)
{
return 驗(yàn)證信息[過期時間戳] as string;
}
/// <summary>
/// 驗(yàn)證用戶輸入的驗(yàn)證碼是否正確
/// </summary>
/// <param name="過期時間戳">驗(yàn)證信息過期時間戳</param>
/// <param name="驗(yàn)證碼">用戶輸入的驗(yàn)證碼</param>
/// <returns>返回錯誤信息,如驗(yàn)證成功則返回null</returns>
public static string 驗(yàn)證(DateTime 過期時間戳, string 驗(yàn)證碼)
{ if (過期時間戳 < DateTime.Now) return "驗(yàn)證信息已過期";
var 驗(yàn)證碼明文 = 獲取(過期時間戳);
if (驗(yàn)證碼明文 == null) return "驗(yàn)證信息無效或已過期";
else if (驗(yàn)證碼明文.ToLower() != 驗(yàn)證碼.ToLower()) return "驗(yàn)證碼錯誤";
else return null;
}
/// <summary> /// 根據(jù)過期時間戳移除對應(yīng)的驗(yàn)證信息 /// </summary>
/// <param name="過期時間戳">驗(yàn)證信息過期時間戳</param> public static void 移除(DateTime 過期時間戳)
{ 驗(yàn)證信息.Remove(過期時間戳); } 使用方法: 使用時在頁面上封裝一個基于ViewState屬性: /// <summary> /// 時間戳屬性,基于ViewState /// </summary>
public DateTime? 時間戳
{ get
{ return ViewState["時間戳"] as DateTime?;
} set { ViewState["時間戳"] = value; } }
然后在load事件中調(diào)用: protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{ 時間戳 = 提交驗(yàn)證.添加(); Image1.ImageUrl = "~/VerifyImage.aspx?ID=" + 時間戳.Value.ToFileTime(); }
}
(無參數(shù)的“添加”方法是我實(shí)現(xiàn)的一個適配器封裝方法,采用默認(rèn)的過期時間設(shè)置,隨機(jī)生成驗(yàn)證碼)
提交時的調(diào)用:
protected void Button1_Click(object sender, EventArgs e)
{ var s = 提交驗(yàn)證.驗(yàn)證(時間戳.Value, TextBox1.Text);
if (s == null)
{ CustomValidator1.IsValid = true; //提交... 提交驗(yàn)證.移除(時間戳.Value);
} else
{ CustomValidator1.IsValid = false;
CustomValidator1.ErrorMessage = s;
}
}
|