ASP.NET防使用者重複登入的方法
本例完成的功能就是防止使用者重複登入!若使用者已經登入,則當其再次登入時,彈出提示框後返回!
實現思路:
使用者登入成功後,將使用者登入資訊存放到Hashtable型別的Application[“Online”]裡面,其鍵值為SessionID,其Value值為使用者ID;當用戶登出時,呼叫Session.Abandon;在Global.asax裡面的SessionEnd事件中,將使用者ID從Hashtable中刪除;在使用者訪問頁面時,察看Hashtable中是否有對應的使用者ID如果沒有則判斷使用者不線上(使用者不線上的原因可能是按了登出按鈕、網頁超時等)
1、公用類中判斷使用者是否線上的函式(供使用者呼叫)
/**//// <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、使用者登入事件處理:
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事件:
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、在每一個頁面需要重新整理的地方,呼叫如下程式碼:
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地址一起存進去,
則在將相應資訊取出來分析的時候,可以做到:當用戶在不同的計算機上先後登入的時候,則允許最近一次的登入,而將之前的登入刪除!等等
以上方法對於正常退出的檢測是可行的,但是對於非正常退出的方法不行。
非正常退出包括 ,直接關閉 瀏覽器 。這時候 Global.asax中的Session_End 的事件就不會被觸發,由於Session值的消失要20分鐘左右,因此在這20分鐘內,系統無法判斷客戶端是否已經退出,只能作為使用者仍然線上來對待。也就是說,這20分鐘內,該使用者無法再次登入,必須等20分鐘後,方可正常登入。
解決方案查到如下三種
一 : 後登陸的踢出先登入的。
在 Application 中儲存線上使用者時,也儲存一下登入時刻 ,當 後期有使用者登入時 ,就更新登入時刻 ,若 之前使用者 比較時 發現 自己的登入時刻 跟 儲存的 不一致 時 ,將提示 已被踢出。
二 : 使用Javascript方式
在每一個頁面中加入一段javascript程式碼:
function window.onbeforeunload()
{
if (event.clientX>document.body.clientWidth && event.clientY<0||event.altKey){
window.open("logout.aspx");
}
}
由於onbeforeunload方法在瀏覽器關閉、重新整理、頁面調轉等情況下都會被執行,所以需要判斷是點選了關閉按鈕或是按下Alt+F4時才執行真正的關閉操作。
然後在logout.aspx的Page_Load中寫和Session_End相同的方法,同時在logout.aspx中加入事件:onload=”javascript:window.close()”
但是這樣還是有問題,javascript在不同的瀏覽器中可能有不同的行為,還有就是當通過檔案->關閉時沒有判斷到。
三: 使用xmlhttp方法(這種方法測試下來沒有問題)
在每個頁面中加入如下的javascript(這些javascript也可以寫在共通裡,每個頁面引入就可以了)
var x=0;
function myRefresh()
{
var httpRequest = new ActiveXObject("microsoft.xmlhttp");
httpRequest.open("GET", "test.aspx", false);
httpRequest.send(null);
x++;
if(x<60) //60次,也就是Session真正的過期時間是30分鐘
{
setTimeout("myRefresh()",30*1000); //30秒
}
}
myRefresh();
在web.config中設定
<sessionState mode="InProc" timeout="1"></sessionState>
test.aspx頁面就是一個空頁面,只不過需要在Page_Load中加入:
Response.Expires = -1;
保證不使用快取,每次都能呼叫到這個頁面。
原理就是:設定Session的過期時間是一分鐘,然後在每個頁面上定時每30秒連線一次測試頁面,保持Session有效,總共連60次,也就是30分鐘。如果30分鐘後用戶還沒有操作,Session就會過期。當然,如果使用者直接關閉瀏覽器,那麼一分鐘後Session也會過期。這樣就可以滿足要求了。
但是 缺點很明顯。