Question

I have a project running MVC4 and using Simple Membership for authentication. I only want to allow a user to login on one browser. To make this transparent to the user, I need a way to have any other authenticated browser log out whenever a user logs in. This means, if two users are trying to use the same login, they would just continuously kick each other off making that very unproductive.

Right now, I have it set up to only allow a user to login once but if that user were to close the browser and move to another computer, they would be locked out for 30 minutes I can see this creating a number of unnecessary support calls.

I would assume I need to track some sort of identifier in a database and check to make sure it matches with each request otherwise they are logged out. Maybe, adding some sort of cookie.

If anyone has an elegant solution to this, I would appreciate it!

This is what I am currently using to lock users into only one login:

Login:

[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];
        }
    }
}

Logout:

[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");
}

I had used the term session and have removed it. I'm not trying to delete the user's session but make their authorization invalid using web security.

Was it helpful?

Solution

There's nothing built-in for this. You'd have to develop some methodology on your own. You'd basically need two pieces:

  1. Some way of tracking a logged in user across requests. This could be as simple as a table with a username column which you could use to determine if that particular username has been logged in. You'd need to keep this in sync with your logins/logouts of course, and you would also need to store the session id for the user. You'll need that for the next piece:

  2. Some mechanism of removing the session from whatever store it exists in. This would be easiest if you're using SQL sessions, as you could simply delete the row from the table session table with the matching id. There's no way to do this directly with ASP.NET, so you'd have to directly query the database, used a stored procedure, etc.

So, the general idea would be that when a user logs in, you record their username and session id in a table or some other persisted store. When someone attempts to log in, you'd check this store for the username that is being attempted, and if it exists, go delete the session that corresponds to this. The next time the user with that session tries to access a page, their session cookie will no longer match a valid session and they'll be treated as if they've been logged out.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top