登录时记录所有其他浏览器

时间:2014-07-28 17:12:39

标签: asp.net asp.net-mvc asp.net-mvc-4 simplemembership

我有一个运行MVC4并使用Simple Membership进行身份验证的项目。我只想允许用户在一个浏览器上登录。为了使这对用户透明,我需要一种方法让任何其他经过身份验证的浏览器在用户登录时注销。这意味着,如果两个用户尝试使用相同的登录,他们只会不断地互相攻击非常没有效果。

现在,我将其设置为仅允许用户登录一次但是如果该用户要关闭浏览器并移动到另一台计算机,则他们将被锁定30分钟我可以看到这创建了一些不必要的支持电话。

我认为我需要在数据库中跟踪某种标识符并检查以确保它与每个请求匹配,否则它们将被注销。也许,添加某种cookie。

如果有人对此有一个优雅的解决方案,我将不胜感激!

这是我目前用来锁定用户只能登录一次的内容:

登录:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
    string sKey = model.UserName;
    string sUser = Convert.ToString(System.Web.HttpContext.Current.Cache[sKey]);

    if (sUser == null || sUser == String.Empty)
    {
        TimeSpan SessTimeOut = new TimeSpan(0, 0, System.Web.HttpContext.Current.Session.Timeout, 0, 0);
        System.Web.HttpContext.Current.Cache.Insert(sKey, sKey, null, DateTime.MaxValue, SessTimeOut, System.Web.Caching.CacheItemPriority.NotRemovable, null);

        Session["user"] = model.UserName;

        if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
        {
            return RedirectToLocal(returnUrl);
        }

        // If we got this far, something failed, redisplay form
        ModelState.AddModelError("", "The user name or password provided is incorrect.");
    }
    else
    {
        ModelState.AddModelError("", "You are already logged in.");
   }

    return View(model);
}

Global.asax中

protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
    if (HttpContext.Current.Session != null)
    {
        if (Session["user"] != (null)) // e.g. this is after an initial logon
        {
            string sKey = (string)Session["user"];
            // replace the last hit with current time
            // Accessing the Cache Item extends the Sliding Expiration automatically
            string sUser = (string)HttpContext.Current.Cache[sKey];
        }
    }
}

注销:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
    UserProfile user = db.UserProfiles.SingleOrDefault(s => s.UserName == User.Identity.Name);
    string sKey = user.UserName;
    System.Web.HttpContext.Current.Cache.Remove(sKey);
    WebSecurity.Logout();
    return RedirectToAction("Start", "Home");
}

我使用了术语会话并删除了它。我没有尝试删除用户的会话,但使用网络安全设置无效。

1 个答案:

答案 0 :(得分:1)

没有内置的东西。你必须自己开发一些方法。你基本上需要两件作品:

  1. 跨请求跟踪已登录用户的某种方式。这可以像具有用户名列的表一样简单,您可以使用该列来确定是否已登录该特定用户名。当然,您需要将此与登录/注销保持同步,并且您还需要存储用户的会话ID。你需要为下一件作品:

  2. 从存在的任何存储中删除会话的一些机制。如果您正在使用SQL会话,这将是最简单的,因为您可以简单地从具有匹配ID的表会话表中删除该行。没有办法直接使用ASP.NET,所以你必须直接查询数据库,使用存储过程等。

  3. 因此,一般的想法是,当用户登录时,您将其用户名和会话ID记录在表或其他一些持久存储中。当有人尝试登录时,您将检查此商店中是否有正在尝试的用户名,如果存在,请删除与此对应的会话。下次具有该会话的用户尝试访问某个页面时,他们的会话cookie将不再与有效会话匹配,并且他们将被视为已被注销。