ASP.net 實現禁止用戶重復登錄


本文先為大家介紹如何利用緩存Cache方便地實現此功能。 
Cache與Session這二個狀態對像的其中有一個不同之處,Cache是一個全局對象,作用的范圍是整個應用程序,所有用戶;
而Session是一個用戶會話對象,是局部對象,用於保存單個用戶的信息。 
只要把每次用戶登錄后的用戶信息存儲在Cache中,把Cache的Key名設為用戶的登錄名,Cache的過期時間設置為Session的超時時間,在用戶每次登錄的時候去判斷一下Cache[用戶名]是否有值,如果沒有值,證明該用戶沒有登錄,否則該用戶已登錄。
為大家舉一個例子吧。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/// <summary>
/// 防止多次登錄
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button1_Click( object sender, System.EventArgs e)
{
string strUser = string .Empty;
string strCacheKey = this .TextBox1.Text;
 
strUser = Convert.ToString(Cache[strCacheKey]);
 
if (strUser == string .Empty)
{
TimeSpan SessTimeOut = new TimeSpan(0, 0, System.Web.HttpContext.Current.Session.Timeout, 0, 0);
 
Cache.Insert(strCacheKey, strCacheKey, null , DateTime.MaxValue, SessTimeOut, CacheItemPriority.NotRemovable, null );
Session[ "User" ] = strCacheKey;
this .Label1.Text = Session[ "User" ].ToString();
}
else
{
this .Label1.Text = "這個用戶已經登錄!" ;
}
}

在網上又找了下,發現了另外兩種解決方案:
1、通過數據庫狀態位判斷該用戶是否已經登錄。
2、利用session監聽器監聽每一個登錄用戶的登錄情況。
第一種解決方案很簡單,但需要考慮用戶非正常退出的情況,如直接關閉瀏覽器等等,可用性較低。
接下來,主要介紹第二種方案的具體實現:利用session監聽器監聽每一個登錄用戶的登錄情況。
A.用戶登錄后,先去數據庫查詢該登錄名是否存在、是否鎖定,在登錄名存在且非鎖定的情況下,從application內置作用域對象中取出所有的登錄信息,查看該登錄名是否已經登錄,如果登錄了,就友好提示下;反之表示可以登錄,將該登錄信息保存在application中。
主要代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//
//所有的登錄信息
Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP);
boolean isExist = false ;
String sessionId = super.getSessionId( false );
if (loginUserMap== null ){
loginUserMap = new HashMap<String, String>();
}
for (String username : loginUserMap.keySet()) {
//判斷是否已經保存該登錄用戶的信息,是否為同一個用戶進行重復登錄
if (!username.equals(user.getFuUserName()) || loginUserMap.containsValue(sessionId)){
continue ;
}
isExist = true ;
break ;
}
if (isExist){
//該用戶已登錄
//
} else {
//該用戶沒有登錄
loginUserMap.put(result.getFuUserName(), sessionId);
//
}
//

B.登錄考慮完之后,來考慮考慮退出。
用戶正常退出時,我們需要將該用戶的登錄信息從session中移除。我們可以寫一個Session監聽器,監聽sessioon銷毀的時候,我們將登錄的用戶注銷掉,也就是從application中移除。表示該用戶已經下線了。

主要代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
//
public void sessionDestroyed(HttpSessionEvent event ) {
   // 
   //在session銷毀的時候 把loginUserMap中保存的鍵值對清除
   User user = (User) event .getSession().getAttribute( "loginUser" );
   if (user!= null ){
     Map<String, String> loginUserMap = (Map<String, String>) event .getSession().getServletContext().getAttribute( "loginUserMap" );
     loginUserMap.remove(user.getFuUserName());
event .getSession().getServletContext().setAttribute( "loginUserMap" ,loginUserMap);
   }
   //
}
//

另外,還有一個問題,如果說登錄的用戶突然關閉了瀏覽器而沒有點擊退出按鈕。那么可以利用beforeunload 事件,在瀏覽器刷新或者關閉的時候觸發。

?
1
2
3
4
5
6
7
8
9
10
//在刷新或關閉時調用的事件
$(window).bind( 'beforeunload' ,function(){
  $.ajax({
   url: "${ctx}/system/user/user!logout.action" ,
   type: "post" ,
   success:function(){
    alert( "您已退出登錄" );
   }
  });
});

這樣基本就實現了需求。
大家可以把上面代碼運用到自己的項目中,檢測一下,有效的防止同一賬號的重復登錄,希望大家喜歡這些方法。

ASP.net 實現禁止用戶重復登錄(踢出先登錄的)

應客戶要求,須在系統中實現禁止用戶重復登錄。

我采用的是asp.net自帶的登錄組件,有很多現成屬性和方法可用,比如,Membershipuser.Comment可用來存儲用戶的特定登錄信息,本例中的時間刻錄,就存儲在這個屬性中。注意,存儲后,記得用Membership.UpdateUser 方法來保存信息。

如果沒有采用asp.net自帶的登錄組件,則可通過Application或數據庫來保存,其原理是一樣的。

為了解決用戶提出的“禁止同一用戶名重復登錄”的要求,曾經采用更兩種解決方案。

最初采用的方案,是利用MembershipUser.IsOnline 來判斷用戶是否在線,如果在線,則禁止登錄。

If sUser.IsOnline Then

Me.CustomValidator1.ErrorMessage = "該用戶已經在另一地點登錄!"
           args.IsValid = False
           Exit Sub
    End If

 

 

但是,這一方案有一缺點,當用戶非正常退出時,由於Session值的消失要20分鍾左右,因此在這20分鍾內,系統無法判斷客戶端是否已經退出,只能作為用戶仍然在線來對待。也就是說,這20分鍾內,該用戶無法再次登錄,必須等20分鍾后,方可正常登錄。

這樣明顯無法滿足客戶要求。所以,后來我就采用了第二種方案:后登錄的用戶,踢出先登錄的用戶。

第二種方案的實現原理如下:

1.登錄時在User.Comment中保存登錄的時間刻度,同時在Session中保存同一刻度數。代碼如下:
        If Membership.ValidateUser(sUserName, sPassword) Then

 

Dim sLoginTicks As String = Now.Ticks.ToString
            sUser.Comment = sLoginTicks
            Membership.UpdateUser(sUser)  '保存到User.comment值中
            Page.Session.Add("LoginTicks", sLoginTicks) '保存到Session中

 

FormsAuthentication.SetAuthCookie(sUserName, False)
            Response.Redirect("Default.aspx")
        Else
            Response.Write("<script> alert(""用戶名或密碼錯誤!"");location.href = """ & Request.Url.ToString & """;</script>")
            Response.End()
        End If

 

2.在頁面登錄驗證時,對比Session中時間刻度,和User.comment中的時間刻度是否相同。后登錄的,這兩個值同時被更新,必定會相同。而先登錄的用戶,由於Session中的值未更新,而User.comment中的值,被后登錄的用戶更新掉了,因此值不同,從而被踢出。代碼如下:

Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
       Dim HomePage As String = Me.ResolveUrl("~/Default.aspx")
        If Page.Request.IsAuthenticated = True Then '本句用來驗證是否登錄
            Dim sUser As MembershipUser = Membership.GetUser
            If Page.Session("LoginTicks") IsNot Nothing Then
                If Me.Page.Session("LoginTicks").ToString <> sUser.Comment.ToString Then
                    FormsAuthentication.SignOut()
                    Response.Write("<script> alert(""相同帳號在其它地點登錄,你被迫注銷。如有疑問,請與網站管理員聯系。"");location.href = """ & HomePage & """;</script>")
                    Response.End()
                End If
            End If
        End If

 

End Sub

經測試,該方案完美解決了禁止用戶重復登錄的問題

 

二、

實現思路:
用戶登錄成功后,將用戶登錄信息存放到Hashtable類型的Application["Online"]里面,其鍵值為SessionID,其Value值為用戶ID;當用戶注銷時,調用Session.Abandon;在Global.asax里面的SessionEnd事件中,將用戶ID從Hashtable中刪除;在用戶訪問頁面時,察看Hashtable中是否有對應的用戶ID如果沒有則判斷用戶不在線(用戶不在線的原因可能是按了注銷按鈕、網頁超時等)

1、公用類中判斷用戶是否在線的函數(供用戶調用)
Code
 /**//// <summary> 
 /// 判斷用戶strUserID是否包含在Hashtable h中 
 /// </summary> 
 /// <param name="strUserID"></param> 
 /// <param name="h"></param> 
 /// <returns></returns> 
 public static bool AmIOnline(string strUserID, Hashtable h)
 {
     if (strUserID == null)
        return false;

    //繼續判斷是否該用戶已經登陸 
    if (h == null)
        return false;

    //判斷哈希表中是否有該用戶 
    IDictionaryEnumerator e1 = h.GetEnumerator();
    bool flag = false;
    while (e1.MoveNext())
    {
        if (e1.Value.ToString().CompareTo(strUserID) == 0)
        {
            flag = true;
            break;
        }
    }
    return flag;
}

2、用戶登錄事件處理:
Code
private void btnlogin_Click(object sender, System.Web.UI.ImageClickEventArgs e)

    //User為自定義的類,其中包含Login方法
    User CurUser = new User();
    CurUser.UserID = this.username.Text.Trim();

    if (MyUtility.AmIOnline(CurUser.UserID, (Hashtable) Application["Online"]))
    {
        JScript.Alert("您所使用的登錄ID已經在線了!您不能重復登錄!");
        return;
    }

    CurUser.LoginPsw = FormsAuthentication.HashPasswordForStoringInConfigFile(this.password.Text.Trim(), "SHA1");
    int ii = CurUser.Login();
    StringBuilder sbPmt = new StringBuilder();

    switch (ii)
    {
    case 0: //如果登錄成功,則將UserID加入Application["Online"]中
        Hashtable h = (Hashtable) Application["Online"];
        if (h == null)
            h = new Hashtable();
        h[Session.SessionID] = CurUser.UserID;
        Application["Online"] = h;

        Session["UserID"] = CurUser.UserID;
        Session["UserNM"] = CurUser.UserNM;
        Session["RoleMap"] = CurUser.RoleMap;
        Session["LoginPsw"] = CurUser.LoginPsw;
        Session["LoginTime"] = DateTime.Now;
        Response.Redirect("ChooseRole.aspx");
        break;
    case -1:
        JScript.Alert("用戶名錯誤!");
        break;
    case -2:
        JScript.Alert("密碼錯誤!");
        break;
    default:
        sbPmt.Append("登錄過程中發生未知錯誤!");
        JScript.Alert(sbPmt.ToString());
        break;
    }
    return;
}

3、在Global.asax中的Session_End事件:
Code
protected void Session_End(Object sender, EventArgs e)
{
    Hashtable h = (Hashtable) Application["Online"];

    if (h[Session.SessionID] != null)
        h.Remove(Session.SessionID);

    Application["Online"] = h;
}

4、在每一個頁面需要刷新的地方,調用如下代碼:
Code
try
{
    if (!common.MyUtility.AmIOnline(Session["UserID"].ToString(), (Hashtable) Application["OnLine"]))
    {
        //用戶沒有在線 ,轉到登錄界面
        Response.Write("<script>parent.document.location.href='Login.aspx';</script>"); ////有框架時用
        //Response.Redirect("login.aspx"); ////無框架時用
        return;
    }
}
catch
{
    //會話過期 ,轉到登錄界面
    Response.Write("<script>parent.document.location.href='Login.aspx';</script>"); ////有框架時所用
    //Response.Redirect("login.aspx"); ////無框架時用
    return;
}

深入思考:

由本例的解決方法可以加以延伸,比如,在存儲UserID的時候,將UserID+客戶端IP地址一起存進去,

則在將相應信息取出來分析的時候,可以做到:當用戶在不同的計算機上先后登錄的時候,則允許最近一次的登錄,而將之前的登錄刪除!等等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM