ASP.NET Web Form Single Login

會有這樣的題目主要是因為業主的要求(廢話)。明確的說是這樣的,同一時間同一帳號只能在一個地方登入,之後登入的可以把前面登入的剔除。這個機制其實之前我並沒有想到要怎麼解,或是說沒想到不用資料庫的方式要怎麼解…(超遜的啦!)。不過認真想過後才發現這個機制其實不會太難,或是說我的解法其實很簡單,而且應該也可以用在MVC架構裡。 研究方法 Session ASP.NET提供Session讓我們可對工作狀態進行管理,可以讓我們跨越多個要求儲存與瀏覽器工作階段關連的訊息,Session提供Key-value pairs的方式來存取這些資料。雖然我們很常拿Session來儲存使用者的資訊,像是使用者的帳號或是一些其他資訊,不過Session是每個使用者各自有的,這裡面的資訊並不會共享,因此利用Session來達成需求顯然是不行。我們需要的應用系統的全域變數,或是資料結構來對整個系統的使用者進行管理。這樣的需求我想全域應用程式類別(預設檔名為Global.asax)就是我這邊提出的解答! 簡述關於Global.asax的運作 當ASP.NET應用程式收到第一個要求的時候會先使用ApplicationManager建立應用程式定義域(應用程式定義域可以隔離應用程式間的全域變數,而且能夠允許每個應用程式個別進行卸載。)。在所有核心物件初始化後會藉由建立System.Web.HttpApplication類別的實體來執行應用程式。若應用程式中有Global.asax(繼承自HttpApplication)則會改用衍生自HttpApplication的Global.asax來建立執行應用程式的實體。而當處理要求的時候則會執行下述事件:(注意!這邊僅列達成需求出最主要的兩個) 1 2 3 4 5 6 7 8 9 ///當要求ASP.NET應用程式中的第一個資源(如:網頁)時呼叫, ///這個方法在應用程式生命週期中只會被呼叫一次。 ///我們讓全域變數在這邊進行宣告。 Application_Start(object sender, EventArgs e) { } ///這個方法在MSDN裡面的解釋有點怪,不過在應用程式生命週期中該事件發生也是只有一次, ///就是當IIS重啟或是應用程式正常關閉時就會發起該事件。 ///我們讓全域變數所用到的資源在這裡釋放。 Application_End(object sender, EventArgs e) { } 開始撰寫時我們要先準備一下這個管理使用者的容器類別: 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 /// 系統中記錄目前線上全部使用者的識別號的容器。 public sealed class SystemUserPool { private static ConcurrentDictionary<string, string> _UserPool = new ConcurrentDictionary<string, string>(); /// 記錄系統中新登入的使用者。 /// userNumber = 登入者的帳號。 /// userIp = 登入者的 IP 位址。 /// 使用者登入成功與否。 public Boolean AddUser(String userNumber, String userIp) { return _UserPool.TryAdd(userNumber, userIp); } /// 剔除系統中指定的使用者。 /// userNumber = 使用者的帳號。 /// 剔除成功與否。 public Boolean DeleteUser(String userNumber) { string str = String.Empty; return _UserPool.TryRemove(userNumber, out str); } /// 列出目前系統中在線上的使用者。 /// 使用者列表。 public List<string> ListAllUser() { return _UserPool.Keys.ToList<string>(); } /// 判斷使用者是否仍在線上。 /// userNumber = 欲查明的使用者。 /// 若在線上則為 true,反之則為 false。 public Boolean IsOnLine(String userNumber) { return _UserPool.Keys.Contains(userNumber); } /// 判斷使用者是否從同一個地方登入。 /// userNumber = 使用者帳號。 /// userIp = 使用者目前 IP 位址。 /// 若 userIp 與系統中使用者的 IP 位址一致表示從同一個地方登入。 public Boolean IsTheSameIP(String userNumber, String userIp) { String orignalIP = String.Empty; if (_UserPool.TryGetValue(userNumber, out orignalIP)) { if (orignalIP == userIp) return true; return false; } return false;//若沒能取得,表示使用者已經離線。 } /// 更新使用者的 IP 位址。 /// userNumber = 使用者帳號。 /// userIP = 使用者新的 IP 位址。 public void UpdateUserIP(String userNumber, String userIP) { if (!IsOnLine(userNumber)) return; _UserPool[userNumber] = userIP; } /// 把系統使用者儲蓄池清空。 public void ClearUserPool() { _UserPool.Clear(); } } 在Application_Start中就這樣寫: ...

September 3, 2012 · 2 分鐘 · 336 字