Asp.net 实现只能允许一个账号同时只能在一个地方登录

先上帮助类:

/// <summary>
    /// 单点登录帮助类
    /// </summary>
    public class SSOHelper
    {
        /// <summary>
        /// 登录后执行
        /// </summary>
        /// <param name="UserID">用户标识</param>
        public void LoginRegister(string UserID)
        {
            Hashtable hOnline = (Hashtable)System.Web.HttpContext.Current.Application["Online"];
            if (hOnline != null)
            {
                IDictionaryEnumerator idE = hOnline.GetEnumerator();
                string strKey = "";
                while (idE.MoveNext())
                {
                    if (idE.Value != null && idE.Value.ToString().Equals(UserID))
                    {
                        //already login 
                        strKey = idE.Key.ToString();
                        hOnline[strKey] = "XXXXXX";
                        break;
                    }
                }
            }
            else
            {
                hOnline = new Hashtable();
            }

            hOnline[System.Web.HttpContext.Current.Session.SessionID] = UserID;
            System.Web.HttpContext.Current.Application.Lock();
            System.Web.HttpContext.Current.Application["Online"] = hOnline;
            System.Web.HttpContext.Current.Application.UnLock();
        }

        /// <summary>
        /// 检查是否唯一登录
        /// </summary>
        /// <returns></returns>
        public static bool CheckOnline()
        {
            Hashtable hOnline = (Hashtable)System.Web.HttpContext.Current.Application["Online"];
            if (hOnline != null)
            {
                IDictionaryEnumerator idE = hOnline.GetEnumerator();
                while (idE.MoveNext())
                {
                    if (idE.Key != null && idE.Key.ToString().Equals(System.Web.HttpContext.Current.Session.SessionID))
                    {
                        //already login
                        if (idE.Value != null && "XXXXXX".Equals(idE.Value.ToString()))
                        {
                            hOnline.Remove(System.Web.HttpContext.Current.Session.SessionID);
                            System.Web.HttpContext.Current.Application.Lock();
                            System.Web.HttpContext.Current.Application["Online"] = hOnline;
                            System.Web.HttpContext.Current.Application.UnLock();
                            return false;
                        }
                        break;
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// Global文件的SessionEnd事件中增加此代码
        /// </summary>
        public static void GlobalSessionEnd()
        {
            Hashtable hOnline = (Hashtable)System.Web.HttpContext.Current.Application["Online"];
            if (hOnline[System.Web.HttpContext.Current.Session.SessionID] != null)
            {
                hOnline.Remove(System.Web.HttpContext.Current.Session.SessionID);
                System.Web.HttpContext.Current.Application.Lock();
                System.Web.HttpContext.Current.Application["Online"] = hOnline;
                System.Web.HttpContext.Current.Application.UnLock();
            }
        }

    }

在登录的时候调用一下LoginRegister方法

Global.asax中:

protected void Session_End(object sender, EventArgs e)
        {
            ltGameStore.Common.SSOHelper.GlobalSessionEnd();
        }

剩下的就是在每次客户端对服务器有请求的时候验证当前会话ID是否被注销掉了(被其他用户挤掉)

我用的是一个继承Controller的基类,重写里面的OnAuhorization方法:

/// <summary>
        /// 在进行授权时调用
        /// </summary>
        /// <param name="filterContext"></param>
        protected override void OnAuthorization(AuthorizationContext filterContext)
        {
            //不能应用在子方法上
            if (filterContext.IsChildAction)
                return;

            //如果没有登录,则跳转到登录视图
            if (WorkContext.Action != "login")
            {
                if (!TicketHelper.IsLogin())
                {
                    filterContext.Result = new RedirectResult("/Account/login");
                }
            }

            if (!SSOHelper.CheckOnline())
            {
                filterContext.Result = PromptView("您的账号已在别处登录");
            }


            //如果当前用户不是管理员
            //if (WorkContext.AdminGid == 1)
            //{
            //    if (WorkContext.IsHttpAjax)
            //        filterContext.Result = new ContentResult { Content = "404" };
            //    else
            //        filterContext.Result = new RedirectResult("/");
            //    return;
            //}
        }

注意,这样写的话会有个问题,每次客户端请求的SessionID都不一样,这样就无法校验了,搜了一下解决方法,在重写的Initialize方法(继承Controller的基类中)中不断的注册SessionId:

/// <summary>
        /// 初始化调用构造函数后可能不可用的数据
        /// </summary>
        /// <param name="requestContext"></param>
        protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
            Session["SessionId"] = Session.SessionID;
        }

参考以下:

http://www.cnblogs.com/xlhblogs/archive/2012/03/29/2422804.html

http://czhjq.blog.163.com/blog/static/85014962010112263336615/