Click here to Skip to main content
15,886,806 members
Articles / Web Development / HTML
Tip/Trick

How To Prevent the Same User ID from Logging in From Multiple Devices Using ASP.NET MVC4

Rate me:
Please Sign up or sign in to vote.
4.43/5 (5 votes)
7 May 2013CPOL2 min read 46.9K   14   10   7
This tip describes how to prevent the same User ID from logging in from multiple devices using ASP.NET MVC4.

Introduction

There are a number of apps out there that prevent multiple log-ins- for example, Spotify. Spotify will only allow one log-in at a time, no matter the device. Spotify logs the user ID out of another device (phone, computer, etc.) if the same user ID has logged in to a new device. Out of the box, ASP.NET allows for concurrent log-ins. But, for people that must have this feature because they can't afford to have people share IDs (especially for subscription based services), I created a custom solution to solve this problem.

Using the Code

What I've implemented was when user "Bob" logs in from his PC, and then the same user "Bob" logs in from another location, the log-in from the first location (his PC) will be killed while allowing the second log-in to live. Once a user logs in, it inserts a record into a custom table I created called "Logins". Upon a successful log-in, one record will be inserted into this table with values for "UserId, SessionId, and LoggedIn". UserId is pretty self-explanatory, SessionId is the current Session ID (explained below how to get), and LoggedIn is simply a boolean that's initially set to True upon a successful user log-in. I place this "insert" logic inside my Login method of my AccountController upon successful validation of the user- see below:

C#
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();

For my situation, I want to place the check on each of my controllers to see if the currently logged in user is logged in elsewhere, and if so, kill the other session(s). Then, when the killed session tries to navigate anywhere I placed these checks on, it'll log them out and redirect them to the Log-in screen.

I have three main methods that do these checks:

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

Save Session ID to Session["..."]

Before all of this though, I save the SessionID to the Session collection inside the AccountController, inside the Login ([HttpPost]) method:

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

Controller Code

I then place logic inside my controllers to control the flow of the execution of these three methods. Notice below that if for some reason Session["sessionid"] is null, it'll just simply assign it a value of "empty". This is just in case for some reason it comes back as null:

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

The Three Methods

These are the methods I use to check to see if YOU are still logged in (i.e. make sure you weren't kicked off by another log-in attempt), and if so, check to see if your User ID is logged in somewhere else, and if so, kick them off by simply setting their LoggedIn status to false in the Logins table.

C#
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();
}

That's pretty much it. This has worked like a charm for me. Feel free to redistribute this, modify it to fit your needs, or whatever you need to do.

History

  • 7th May, 2013: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Mike is a web developer for a leading oil and gas company in Oklahoma. He's been writing .NET apps for 4 years and has expertise in ASP.NET with MVC.

Comments and Discussions

 
Questionbrowser close Pin
Member 152813808-Jul-21 2:48
Member 152813808-Jul-21 2:48 
QuestionLogout Dialogbox Or Message Pin
UnStable Messi27-Apr-17 0:03
UnStable Messi27-Apr-17 0:03 
PraiseNice article Pin
Dinesh.V.Kumar4-Apr-16 23:18
Dinesh.V.Kumar4-Apr-16 23:18 
QuestionSession timeout Pin
danmbuen214-Apr-14 0:23
danmbuen214-Apr-14 0:23 
GeneralRe: Session timeout Pin
satish kankerwal13-Aug-18 21:50
satish kankerwal13-Aug-18 21:50 
SuggestionIntegration into Attribute Pin
RobKr7820-Mar-14 21:47
RobKr7820-Mar-14 21:47 
GeneralRe: Integration into Attribute Pin
Member 1127407415-Apr-15 14:09
Member 1127407415-Apr-15 14:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.