延續簡單的重複登入控制(java版)中的思路,用ASP.NET做了類似的實現。
第一步,構造一個簡單的線上會員對象。
[Serializable]public class OnlineMember{ /// <summary> /// MemberID /// </summary> public int MemberID { get; set; } /// <summary> /// SessionID /// </summary> public string SessionID { get; set; } /// <summary> /// 最後通知時間 /// </summary> public DateTime LastNotifyTime { get; set; } /// <summary> /// 登入IP /// </summary> public string LoginIP { get; set; }}
第二步,實現線上會員處理功能。
/// <summary>/// 簡易線上會員功能/// 遵循類似QQ登入的原則:同一帳號登入,總是後登入的擠掉前登入的/// </summary>public class OnlineBiz{ private static Dictionary<int, OnlineMember> _onlineMember = new Dictionary<int, OnlineMember>(); private static object _syncObj = new object(); private static DateTime _lastClearTime = DateTime.Now; /// <summary> /// 添加 /// </summary> /// <param name="MemberID"></param> /// <param name="SessionID"></param> /// <param name="LoginIP"></param> public static void Add(int MemberID, string SessionID, string LoginIP) { lock (_syncObj) { if (_onlineMember.ContainsKey(MemberID)) { _onlineMember.Remove(MemberID); } OnlineMember member = new OnlineMember(); member.MemberID = MemberID; member.SessionID = SessionID; member.LoginIP = LoginIP; member.LastNotifyTime = DateTime.Now; _onlineMember.Add(MemberID, member); } } /// <summary> /// 當前會員是否有效 /// </summary> /// <param name="MemberID"></param> /// <param name="SessionID"></param> /// <returns></returns> public static bool IsValid(int MemberID, string SessionID) { if (!_onlineMember.ContainsKey(MemberID)) return false; if (!_onlineMember[MemberID].SessionID.Equals(SessionID)) return false; _onlineMember[MemberID].LastNotifyTime = DateTime.Now; ClearTimeoutMember(); return true; } /// <summary> /// 移除 /// </summary> /// <param name="MemberID"></param> public static void Remove(int MemberID) { if (_onlineMember.ContainsKey(MemberID)) _onlineMember.Remove(MemberID); } /// <summary> /// 清除逾時會員 /// </summary> private static void ClearTimeoutMember() { int MemberLoginTimeout = int.Parse(ConfigHelper.GetParameterValue("MemberLoginTimeout")); TimeSpan time1 = DateTime.Now - _lastClearTime; if (time1.Minutes > MemberLoginTimeout * 5) { lock (_syncObj) { _lastClearTime = DateTime.Now; foreach (KeyValuePair<int, OnlineMember> kvp in _onlineMember) { TimeSpan time2 = DateTime.Now - kvp.Value.LastNotifyTime; if (time2.Minutes > MemberLoginTimeout) { _onlineMember.Remove(kvp.Key); } } } } }}
第三步,在會員登入成功時將會員放入隊列。
//將當前會員寫入線上列表OnlineBiz.Add(member.MemberID, Session.SessionID, log.LoginIP);
第四步,實現一個線上狀態維護的輪詢功能,比如用AJAX定時讀取某個頁面,該頁面中進行會員有效性檢查。
//當前會員是否有效,重複登入的會員遵循後登入的擠掉前登入的原則if (!OnlineBiz.IsValid(member.MemberID, context.Session.SessionID)){ context.Session.Clear(); context.Response.Write(context.Request.QueryString["jsoncallback"] + "({result: 0})"); return;}
同時,為了保證嚴謹性,使已踢掉的登入不能繼續操作,還可在頁面基類中進行同樣的檢查。
第五步,在用戶端進行提示。
if (json.result == 0) { alert("本帳號已在別處登入,你已被迫下線!"); self.location = "<%=Request.ApplicationPath%>/"; return;}
需要說明的是,“逾時會員清理”採用了一個偷懶且不嚴謹的處理方式:
- 清理動作由輪詢頁面觸發,當後續沒有會員線上的情況下,不會執行該操作。
- 假設會員逾時時間為20分鐘,為了稍許提高效能,My Code每100分鐘以上才會做次掃描,剔除已逾時的會員。
- 假設會員逾時時間為20分鐘,輪詢間隔時間應當小於它,比如設為2分鐘、5分鐘之類的比較合適。
該功能已在實際系統中應用,暫時沒有發現特別的問題,若你採用了這種處理方式,發現其中存在問題,請告知我。