asp.net mvc 簡單實現一個賬號只能在一個地方登錄


原理:

    假設用戶在機器A登陸后,

    這時用戶再次在機器B登陸,會以當前會話的SessionID作為,用戶id作為,插入dictionary集合中,集合再保存在application(保存在服務器的全局變量,多用戶可以共享)變量中,

         同時判斷集合中是否有其他值,這里A機器已經登陸,所以會有A機器登陸的鍵值對,將A機器的鍵對應值修改為“_offline_”,以表示強制下線,

    A機器的頁面通過js輪詢去查詢dictionary集合,發現中SessionID鍵對應的值被修改為“_offline_”,從而注銷登陸,並提示被迫下線。

 

1、global中的代碼:

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }

        //保證同一次會話的SessionID不變
        protected void Session_Start(object sender, EventArgs e) 
        { }

        protected void Session_End(object sender, EventArgs e)
        {
            Hashtable hOnline = (Hashtable)Application["Online"];
            if (hOnline != null)
            {
                if (hOnline[Session.SessionID] != null)
                {
                    hOnline.Remove(Session.SessionID);
                    Application.Lock();
                    Application["Online"] = hOnline;
                    Application.UnLock();
                }
            }
        }
    }
注:保證同一次會話的SessionID不變,這點很重要

2、用戶登陸代碼:
.....

HttpContext httpContext = System.Web.HttpContext.Current;
            var userOnline = 
(Dictionary<string,string>)httpContext.Application["Online"];
            if (userOnline != null)
            {

            IDictionaryEnumerator enumerator = userOnline.GetEnumerator();
            while (enumerator.MoveNext())
            {
              if (enumerator.Value != null && enumerator.Value.ToString().Equals(userID.ToString()))
              {
                userOnline[enumerator.Key.ToString()] = "_offline_";
                break;
              }
            }

            }

else { userOnline = new Hashtable(); } userOnline[Session.SessionID] = userID.ToString(); httpContext.Application.Lock(); httpContext.Application["Online"] = userOnline; httpContext.Application.UnLock(); ......

4、頁面輪詢(可以在母版頁,公共頁)

前台js用的easyui

$(document).ready(function () {
        //定時檢測是否被強制下線
            setInterval(function () {
                CheckIsForcedLogout();
            }, 5000);
    });

    //檢測是否被強制下線
    function CheckIsForcedLogout() {
        $.ajax({
            url: "/Home/CheckIsForcedLogout",
            type: "POST",
            dataType: "json",
            success: function (msg) {
                if (msg.OperateResult == "Success") {
                    $.messager.alert('', msg.OperateData, 'error', function () {
                        window.location.href = "/Account/Login";
                    });
                }
            },
            error: function (ex) { }
        });
    }
 [HttpPost]
        public JsonResult CheckIsForcedLogout()
        {
            try
            {
                HttpContext httpContext = System.Web.HttpContext.Current;
                Hashtable userOnline = (Hashtable)httpContext.Application["Online"];if (userOnline != null)
                {
                    if (userOnline.ContainsKey(httpContext.Session.SessionID))
                    {
                        var value=userOnline[httpContext.Session.SessionID];
                        //判斷當前session保存的值是否為被注銷值
                        if (value != null && "_offline_".Equals(value))
                        {
                            //驗證被注銷則清空session
                            userOnline.Remove(httpContext.Session.SessionID);
                            httpContext.Application.Lock();
                            httpContext.Application["online"] = userOnline;
                            httpContext.Application.UnLock();

                            string msg = "下線通知:當前賬號另一地點登錄, 您被迫下線。若非本人操作,您的登錄密碼很可能已經泄露,請及時改密。";

                            //登出,清除cookie
                            FormsAuthentication.SignOut();

                            return Json(new { OperateResult = "Success", OperateData = msg }, JsonRequestBehavior.AllowGet);
                        }
                    }
                }
                return Json(new { OperateResult ="Failed" }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                return Json(new { OperateResult = "Failed" }, JsonRequestBehavior.AllowGet);
            }
        }

 

這里登陸后,每5秒輪詢服務器(獲取最后登陸時間、ip是從redis緩存讀取,所以輪詢沒有訪問數據庫),然后不訪問數據庫,但是數據量大的話,服務器壓力也是挺大的,暫時沒有更好的解決方案。


免責聲明!

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



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