
此前我介紹了使用資料庫實作的送出驗證方案,一些朋友懷疑其效率不佳,認為Session是更好的方案。
的确使用Session也不會消耗太多記憶體,而且如今記憶體白菜價,最不濟就随手買個2G的插上也就夠了,是以我将在此寫下Session版的實作提要,其餘細節參考前篇。
在Session中存儲一個哈希表用以記錄該使用者的每一條驗證資訊,哈希表的鍵為驗證資訊的過期時間,值為驗證碼的明文。
過期時間使用ViewState存儲,以發給用戶端,并在送出時擷取,以讀取對應的驗證碼明文。
傳給驗證碼生成頁面的ID參數是經ToFileTime()方法轉換的過期時間,驗證碼生成頁擷取到此參數後進行逆轉換,再讀取對應的驗證碼明文以生成顯示。
先建立一個靜态類,名為“送出驗證”,将用于存儲驗證資訊的Session變量封裝為一個屬性:
///
/// 驗證資訊表
static Hashtable 驗證資訊
{
get
{
return Core.函數庫.網絡.Session["驗證資訊"] as Hashtable;
}
set
Core.函數庫.網絡.Session["驗證資訊"] = value;
}
清理方法,用于将過期的資料清除:
/// 清理所有過期的驗證資訊
public static void 清理()
if (驗證資訊 == null || 驗證資訊.Count < 5) return;
foreach (DictionaryEntry f in (Hashtable)驗證資訊.Clone())
if ((DateTime)f.Key < DateTime.Now) 驗證資訊.Remove(f);
小于5條驗證資訊則忽略。
克隆一個驗證資訊表供foreach使用,如果使用原表循環的話,直接移除内容會改變表長度,進而引發異常。
添加方法:
/// 添加一個新的驗證資訊。
/// 驗證碼">要儲存的驗證碼
/// 過期時間內插補點">用于計算過期時間,機關為分鐘
/// 過期時間戳
public static DateTime 添加(string 驗證碼, byte 過期時間內插補點)
清理();
var 過期時間 = DateTime.Now.AddMinutes(過期時間內插補點);
if (驗證資訊 == null) 驗證資訊 = new Hashtable();
驗證資訊.Add(過期時間, 驗證碼);
return 過期時間;
在添加前進行過期資訊清理工作。
擷取、驗證、移除方法:
/// 根據過期時間戳擷取對應的驗證碼
/// 過期時間戳">驗證資訊過期時間戳
/// 驗證碼明文
public static string 擷取(DateTime 過期時間戳)
return 驗證資訊[過期時間戳] as string;
/// 驗證使用者輸入的驗證碼是否正确
/// 驗證碼">使用者輸入的驗證碼
/// 傳回錯誤資訊,如驗證成功則傳回null
public static string 驗證(DateTime 過期時間戳, string 驗證碼)
if (過期時間戳 < DateTime.Now) return "驗證資訊已過期";
var 驗證碼明文 = 擷取(過期時間戳);
if (驗證碼明文 == null) return "驗證資訊無效或已過期";
else if (驗證碼明文.ToLower() != 驗證碼.ToLower()) return "驗證碼錯誤";
else return null;
/// 根據過期時間戳移除對應的驗證資訊
public static void 移除(DateTime 過期時間戳)
驗證資訊.Remove(過期時間戳);
使用時在頁面上封裝一個基于ViewState屬性:
/// 時間戳屬性,基于ViewState
public DateTime? 時間戳
return ViewState["時間戳"] as DateTime?;
ViewState["時間戳"] = value;
然後在load事件中調用:
protected void Page_Load(object sender, EventArgs e)
if (!IsPostBack)
時間戳 = 送出驗證.添加();
Image1.ImageUrl = "~/VerifyImage.aspx?ID=" + 時間戳.Value.ToFileTime();
(無參數的“添加”方法是我實作的一個擴充卡封裝方法,采用預設的過期時間設定,随機生成驗證碼)
送出時的調用:
protected void Button1_Click(object sender, EventArgs e)
var s = 送出驗證.驗證(時間戳.Value, TextBox1.Text);
if (s == null)
CustomValidator1.IsValid = true;
//送出...
送出驗證.移除(時間戳.Value);
else
CustomValidator1.IsValid = false;
CustomValidator1.ErrorMessage = s;
驗證碼生成時,建議隻采用這些字元:2345678abcdefghijkmnprstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ
這裡放棄了一些容易産生視覺混淆的字元,比如1和I、l,0和O、o,減少使用者撓牆、砸電腦的可能。