防止用戶重複登陸系統

很多系統要求防止用戶被重複登陸,我們通常思維是當有用戶重複登陸時要禁止他再登陸進去,
提示他該賬號已經有人在使用中.
然而這樣有個問題很難解決,就是系統很難實時捕捉到該賬號是否還在使用中,
如當用戶非正常退出或者遇到停電等,系統只好等到Session超時後才能知道該賬號已經下線.
在Session超時之前這段時間之內沒有人使用賬號但也沒人再能登陸上去,只能乾等着了.

我的解決方法是模仿QQ的被迫下線的功能。只要你QQ號和密碼正確,隨時都可以登陸上去,但是如果
該QQ號此前有人在使用的話那先前的人就會被擠下去。我們這樣來實現系統防止用戶重複登陸的話就可以輕鬆實現。關鍵就是在Application或數據庫中記錄下在線用戶的SessionID,檢測使用者的SessionID是否和Application中記錄的該用戶ID相對應的SessionID相同,若不相同則提示下線!

用戶登陸成功時用戶ID和SessionID寫入Application中。
 

public void WriteToApplication( string UserID )
  {
   DataTable dtUserFlagList = new DataTable();
   try
   {
    dtUserFlagList = (DataTable)Application["UserFlagList"];
   }
   catch
   {
    dtUserFlagList = null;
   }

   if( dtUserFlagList == null )
   {
    DataColumn dc0 = new DataColumn("UserID",typeof(System.String));
    DataColumn dc1 = new DataColumn("SessionID",typeof(System.String));

    dtUserFlagList.Columns.Add( dc0 );
    dtUserFlagList.Columns.Add( dc1 );
    dtUserFlagList.Columns.Add( dc2 );

    DataRow drUser = dtUserFlagList.NewRow();
    drUser["UserID"] = UserID; //寫入用戶ID
    drUser["SessionID"] = Session.SessionID;//記錄下SessionID

    dtUserFlagList.Rows.Add( drUser );
   }
   else
   {
    int i = 1;
    foreach( DataRow drUser in dtUserFlagList )
    {
     if( drUser["UserID"].ToString() == UserID )
     {
      drUser["SessionID"] = Session.SessionID;//如果在Application中存在當前用戶ID,則把記錄的SessionID值改爲當前的SessionID
      break;
     }
     i++;
    }
    if( i > dtUserFlagList.Rows.Count )
    {
     DataRow drUser = dtUserFlagList.NewRow();
     drUser["UserID"] = UserID; //寫入用戶ID
     drUser["SessionID"] = Session.SessionID;//記錄下SessionID
  
     dtUserFlagList.Rows.Add( drUser );
    }
   }

   Application.Lock();
   Application["UserFlagList"] = dtUserFlagList; //記錄到Application中
   Application.UnLock();

   Session["UserID"] = UserID;//把相關登陸信息寫入Session
  }

下一步我們只要檢測Application中記錄的SessionID是否和當前的SessionID相同就可以了
我在這裏寫了一個頁面的基類,每個頁面繼承這個類。這個類改寫OnLoad()事件,加入檢測SessionID值
public class PageBase : System.Web.UI.Page
{
 public PageBase()
 {
  //
  // TODO: 在此處添加構造函數邏輯
  //
 }

 protected override void OnLoad(EventArgs e)
 {
  base.OnLoad (e);
  if( ! IsPostBack )
  {
   if( Session["UserID"] == null )
   {
    Response.Redirect("Login.aspx");//沒有登陸
    return;
   }
   DataTable dtUserFlagList = (DataTable)Application["UserFlagList"];
   foreach( DataRow drUser in dtUserFlagList )
   {
    if( drUser["UserID"].ToString() == Session["UserID"].ToString() )
    {
     if( drUser["SessionID"].ToString() == Session.SessionID )
      break;//SessionID值相同,沒有其他用戶登陸
     else
     {
      Session.Abandon();//SessionID不相同,有人在使用該賬號,被迫下線
      Response.Redirect("ShowError.aspx?action=該賬號已在別處登陸",false);
     }
    }
   }
  }
 } 
}

 當用戶正常退出系統或非正常退出Session超時,在Application中清除該賬號的記錄
 以下代碼寫在Global.asax.cs文件Session_End方法中
 protected void Session_End(Object sender, EventArgs e)
 {
  if( Session["UserID"] == null )
   return;
  
  DataTable dtUserFlagList = (DataTable)Application["UserFlagList"];
  foreach( DataRow drUser in dtUserFlagList )
  {
   if( drUser["UserID"].ToString() == Session["UserID"].ToString() && drUser["SessionID"].ToString() == Session.SessionID )
   {
    //當UserID和SessionID都和退出用戶的值相等時才清除記錄。
    drUser.Delete();
    break;
   }
  }
  dtUserFlagList.AcceptChanges();

  Application.Lock();
  Application["UserFlagList"] = dtUserFlagList; //將更改記錄到Application中
  Application.UnLock();
 }

 以上方法已經在我的系統中實現,在我的系統可以設定某個賬號同時登陸多少人,只是在記錄中多了一個字段amount。
 這個方法可能不好的地方就是每訪問一個頁面都要檢測是否SessionID值相等,
 不過我覺得讀取Application並不會太大影響系統的效率,這樣可以“實時”地檢測到用戶是否重複登陸

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章