c# - 当同一个用户 ID 试图在多个设备上登录时,如何终止另一台设备上的 session ?

标签 c# asp.net-mvc-4 asp.net-membership session-state sqlmembershipprovider

我想做的是限制用户 ID 一次只能登录一台设备。例如,用户 ID“abc”登录到他们的计算机。用户 ID“abc”现在尝试从他们的手机登录。我想要发生的是终止他们计算机上的 session 。

Spotify 应用正是这样做的 - Spotify 一次只允许一个用户 ID 在一台设备上登录。

我正在使用 ASP.NET 成员资格 (SqlMembershipProvider) 和表单例份验证。

我已经试验过 session 变量,但我不确定从这里到哪里去。

最佳答案

我想出了一个非常棒的解决方案。我实现的是当用户“Bob”从他们的 PC 登录,然后同一个用户“Bob”从另一个位置登录时,从第一个位置(他们的 PC)登录将被终止,同时允许第二个位置登录生活。用户登录后,它会将一条记录插入到我创建的名为“登录”的自定义表中。成功登录后,将向该表中插入一条记录,其中包含“UserId、SessionId 和 LoggedIn”的值。 UserId 是不言自明的,SessionId 是当前 session ID(在下面解释了如何获取),而 LoggedIn 只是一个 bool 值,在用户成功登录时初始设置为 True。在成功验证用户后,我将这个“插入”逻辑放在我的 AccountController 的登录方法中 - 见下文:

Logins login = new Logins();
login.UserId = model.UserName;
login.SessionId = System.Web.HttpContext.Current.Session.SessionID;;
login.LoggedIn = true;

LoginsRepository repo = new LoginsRepository();
repo.InsertOrUpdate(login);
repo.Save();

对于我的情况,我想检查我的每个 Controller 以查看当前登录的用户是否在其他地方登录,如果是,则终止其他 session 。然后,当被杀死的 session 试图导航到我放置这些检查的任何地方时,它会将它们注销并将它们重定向到登录屏幕。

我主要使用三种方法来进行这些检查:

IsYourLoginStillTrue(UserId, SessionId);
IsUserLoggedOnElsewhere(UserId, SessionId);
LogEveryoneElseOut(UserId, SessionId);

将 session ID 保存到 session ["..."]

不过,在所有这些之前,我将 SessionID 保存到 AccountController 中的 session 集合中,在 Login ([HttpPost]) 方法中:

if (Membership.ValidateUser(model.UserName, model.Password))
{
     Session["sessionid"] = System.Web.HttpContext.Current.Session.SessionID;
...

Controller 代码

然后我在我的 Controller 中放置逻辑来控制这三个方法的执行流程。请注意,如果由于某种原因 Session["sessionid"]null,它只会简单地为其分配一个值“empty”。这只是为了以防万一由于某种原因它返回为 null:

public ActionResult Index()
{
    if (Session["sessionid"] == null)
        Session["sessionid"] = "empty";

    // check to see if your ID in the Logins table has LoggedIn = true - if so, continue, otherwise, redirect to Login page.
    if (OperationContext.IsYourLoginStillTrue(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString()))
    {
        // check to see if your user ID is being used elsewhere under a different session ID
        if (!OperationContext.IsUserLoggedOnElsewhere(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString()))
        {
            return View();
        }
        else
        {
            // if it is being used elsewhere, update all their Logins records to LoggedIn = false, except for your session ID
            OperationContext.LogEveryoneElseOut(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString());
            return View();
        }
    }
    else
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Login", "Account");
    }
}

三种方法

这些是我用来检查您是否仍在登录的方法(即确保您没有被另一次登录尝试踢掉),如果是,请检查您的用户 ID 是否已登录在其他地方,如果是这样,只需在登录表中将他们的 LoggedIn 状态设置为 false 即可将他们踢走。

public static bool IsYourLoginStillTrue(string userId, string sid)
{
    CapWorxQuikCapContext context = new CapWorxQuikCapContext();

    IEnumerable<Logins> logins = (from i in context.Logins
                                  where i.LoggedIn == true && i.UserId == userId && i.SessionId == sid
                                  select i).AsEnumerable();
    return logins.Any();
}

public static bool IsUserLoggedOnElsewhere(string userId, string sid)
{
    CapWorxQuikCapContext context = new CapWorxQuikCapContext();

    IEnumerable<Logins> logins = (from i in context.Logins
                                  where i.LoggedIn == true && i.UserId == userId && i.SessionId != sid
                                  select i).AsEnumerable();
    return logins.Any();
}

public static void LogEveryoneElseOut(string userId, string sid)
{
    CapWorxQuikCapContext context = new CapWorxQuikCapContext();

    IEnumerable<Logins> logins = (from i in context.Logins 
                                  where i.LoggedIn == true && i.UserId == userId && i.SessionId != sid // need to filter by user ID
                                  select i).AsEnumerable();

    foreach (Logins item in logins)
    {
        item.LoggedIn = false;
    }

    context.SaveChanges();
}

编辑 我还想补充一点,此代码忽略了“记住我”功能的功能。我的要求不涉及此功能(事实上,出于安全原因,我的客户不想使用它)所以我只是将其排除在外。不过,通过一些额外的编码,我很确定可以考虑到这一点。

关于c# - 当同一个用户 ID 试图在多个设备上登录时,如何终止另一台设备上的 session ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15903574/

相关文章:

asp.net - 如何从成员(member)提供商处获取用户/个人资料列表?

c# - 位数组与运算

asp.net-mvc-3 - 是否可以将 DELETE 作为 ASP.NET MVC3+ 的 Http 动词?

c# - 如何通过 C# post 请求上传文件?自己的云

c# - 如何解决无法连接到 SQL Server 数据库?

asp.net-mvc - ASP.Net MVC 4 - 发现多个类型与名为 'Home' 的 Controller 匹配。

ASP.NET Identity,多个用户具有相同的用户名,但属于不同的公司。覆盖 FindAsync?

c# - ASP.NET 身份和 ASP.NET 成员身份提供程序 "Mashup"

c# - 单元测试貂

c# - AOT 设备中的 Json.Net 反序列化是否需要空构造函数?