Preventing Multiple, Simultaneous Logins

Keep multiple users from logging in with the same credentials


There might be situations where you want to prevent multiple logins with the same credentials. In this article we'll look at a nice method developed by MODX Forum user Yulianita.


MODX logo

The Problem

There are many sites where you don't care how many users log in simultaneously with the same credentials. At Bob's Guides, you could subscribe and hand out your credentials to friends who might be logged in at the same time you are. I'd rather you didn't do that, but I don't care enough to prevent it. I also don't want to lock users out who might want to try visiting the site in a different browser without bothering to close their current browser.

But suppose that you have a subscription site. Users have to subscribe and pay a fee to visit the paid part of the site. You have reason to believe that people are sharing credentials with others and would like to make sure that won't work.


The Solution

This is another case where I thought I had a solution, but didn't. I thought that checking with $modx->user->hasSessionContext() would spot users trying to log in when someone with the same credentials was already logged in. The flaw in my method is that the second user to log in would get a new session and would not have a session context in that session.

Luckily, MODX Forum user Yulianita came up with a better method this snippet as a postHook on the Login snippet:


/* This first line is for validation.
 * If the user is not logging out,
 *  the user is logging in so logged
    is set to 1
 */
if (!isset($_GET['service'])){
    $formFields = $hook->getValues();
    $username = $formFields['username'];
    $modx->user = $modx->getObject('modUser', array(
        'username' => $username,
    ));
    $profile = $modx->user->getOne('Profile');
    $extended = $profile->get('extended');
    $extended['logged'] = 1;
} else if ($_GET['service'] == 'logout' ){
    /* The user is logging out so logged = 0 */
    $user = $modx->getUser();
    $profile = $modx->user->getOne('Profile');
    $extended = $profile->get('extended');
    $extended['logged'] = 0;
}
    /* Save logged status in extended field */
    $profile->set('extended', $extended);
    $profile->save();
return true;

The strategy is to set the logged extended field of the user's profile to 1 when the user logs in and 0 when the user logs out.

This snippet, used as a preHook on the login snippet, handles a second user trying to log in with the same credentials:


if (!isset($_GET['service'])){
    $formFields = $hook->getValues();
    $username = $formFields['username'];
    $modx->user = $modx->getObject('modUser', array(
        'username' => $username,
    ));

    $profile = $modx->user->getOne('Profile');
    $extended = $profile->get('extended');
    if ($extended['logged'] == '1') {
        /* User is already logged in
           redirect to resource 21 */
        $url = $modx->makeURL('21', 'web', $value, 'full');
        $modx->sendRedirect($url);
    }
}
return true;

If the user is already logged in, the preHook redirects the user to resource 21, where they see a message telling them they are already logged in and can't log in again.

Here is the content of resource 21:

[[!disconnectSession]]
[[+userblocked]] You are already signed on using another browser or device . </br>
<a href="[[~21]]&flag=true&userblock=[[+userblocked]]">Logout from all devices</a>

And here is the code of the disconnectSession snippet:

$loginId = 2; //ID of the Login page
if (isset($_GET['userblocked'])){
    $user = $_GET['userblocked'];
    $output = $modx->setPlaceholder('userblocked', $user);
} else  // if user clicked on the link {
    $user = $_GET['userblock'];
    $modx->user = $modx->getObject('modUser',
        array('username' => $user));
    $modx->log(modX::LOG_LEVEL_ERROR, 'Form Data = ' . $user);
    $profile = $modx->user->getOne('Profile');
    $extended = $profile->get('extended');
    $extended['logged'] = 0;
    $profile->set('extended', $extended);
    $profile->save();

    /* Redirect to login page */
    $url = $modx->makeURL($loginId, 'web', '', 'full');
    $modx->sendRedirect($url);
}

return $output;

Coming Up

In the following series of articles, we'll look at how .htaccess files work. In the next one, we'll get an introduction to .htaccess conditions and rules, and see a handy tool for testing them.



Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)



Comments (0)


Please login to comment.

  (Login)