Jump to content

restrict same user session


benbyf
 Share

Recommended Posts

Is there a way to restrict logins for users so that one user can't be loggedin in two places at the same time?

e.g. auto logout user after inactivity (of say 15 minutes..?), or logout action and disallow login if user still "logged in" somewhere?

Link to comment
Share on other sites

3 hours ago, abdus said:

What do you mean by "logged in at two places at the same time"? How can user login again if it's already logged in? Am I missing something? 

Maybe he means in 2 different browsers? I know sometimes I have a dev site open in chrome and opera so I can be on two different pages in the admin. 

  • Like 1
Link to comment
Share on other sites

 

17 minutes ago, louisstephens said:

2 different browsers

Ah, I totally missed that.

4 hours ago, benbyf said:

auto logout user after inactivity

There's a config field that lets you define session timeout.

/**
 * Session expiration seconds
 * 
 * How many seconds of inactivity before session expires
 * 
 * @var int
 *
 */
$config->sessionExpireSeconds = 86400;

 

4 hours ago, benbyf said:

disallow login if user still "logged in" somewhere?

That would be tricky to implement and probably not be secure at all. But using $input->whitelist you can keep sending and receiving a session id which can be used to identify a session across browsers. Google "cookieless session php".

https://stackoverflow.com/questions/5882401/cookie-less-sessions-in-php
https://stackoverflow.com/questions/14229193/sharing-session-between-different-browsers

I tried playing with $config->sessionFingerprint, but I couldn't make it work as you asked

/**
 * Use session fingerprint?
 * 
 * Should login sessions be tied to IP and user agent?
 * IP fingerprinting may be problematic on dynamic IPs. 
 * Below are the possible values: 
 * 
 * 	0 or false: Fingerprint off
 * 	1 or true: Fingerprint on with default/recommended setting (currently 10). 
 * 	2: Fingerprint only the remote IP
 * 	4: Fingerprint only the forwarded/client IP (can be spoofed)
 * 	8: Fingerprint only the useragent
 * 	10: Fingerprint the remote IP and useragent (default)
 * 	12: Fingerprint the forwarded/client IP and useragent
 * 	14: Fingerprint the remote IP, forwarded/client IP and useragent (all). 
 * 
 * If using fingerprint in an environment where the user’s 
 * IP address may change during the session, you should
 * fingerprint only the useragent, or disable fingerprinting.
 *
 * If using fingerprint with an AWS load balancer, you should 
 * use one of the options that uses the “client IP” rather than 
 * the “remote IP”, fingerprint only the useragent, or disable 
 * fingerprinting.
 * 
 * @var int
 *
 */
$config->sessionFingerprint = 1;

 

  • Like 1
Link to comment
Share on other sites

5 hours ago, benbyf said:

Is there a way to restrict logins for users so that one user can't be loggedin in two places at the same time?

e.g. auto logout user after inactivity (of say 15 minutes..?), or logout action and disallow login if user still "logged in" somewhere?

Maybe how PW checks if the same page is being edited in a different window could be of help? Have a look at the method checkProcessKey() in SystemNotifications module.

  • Like 2
Link to comment
Share on other sites

38 minutes ago, abdus said:

I tried playing with $config->sessionFingerprint, but I couldn't make it work as you asked

Amazing, I'll check this out. My question would be through would it still allow one user logged in using two fingerprints (e.g. logged in on my phone and laptop)?

21 minutes ago, kongondo said:

Maybe how PW checks if the same page is being edited in a different window could be of help? Have a look at the method checkProcessKey() in SystemNotifications module.

Sounds promising.

Link to comment
Share on other sites

OK, so I had a stab at this using $cache and ready.php. It seems to work fine.

Throw the following code in ready.php or similar...The code and in-line comments are purposefully verbose to make it easy to follow.

// Hook into login/logout sessions
wire()->addHookAfter('Session::loginSuccess', null, 'checkLoggedIn');
wire()->addHookBefore('Session::logout', null, 'removeLoggedIn');// Hook before to get $user->id

/**
 * Check if a user is already logged in
 *
 * If user logged in, take an action (notify,logout,etc).
 * Else, cache user as logged in to check for duplicate logins.
 * 
 * @param HookEvent $event The object (Session::loginSuccess) we are hooking into.
 * @return void
 * 
 */
function checkLoggedIn(HookEvent $event) {
    
    $user = $event->arguments('user');
    $session = wire('session');

    $userDuplicateLogin = checkUserDuplicateLogin($user);// returns boolean
    // if user logged in, do something. Here, we log them out and redirect to home page
    // you could make an exception for Superusers, or exception by role, permission, etc
    if($userDuplicateLogin) {
        $session->logout();
        $session->redirect('/');
     }
     // set cache
     else setLoggedInUserCache($user);
    /* @note: testing only
    $log = wire('log');
    $log->save("user-logs","Successful login for '$user->name'"); */

}

/**
 * Check if a user is logged in more than once.
 *
 * @param User $user The user to whose logins to check.
 * @return Boolean $duplicateLogIn True if user already logged in, else false.
 * 
 */
function checkUserDuplicateLogin(User $user) {    
    $cache = wire('cache');
    $duplicateLogIn = false;
    $userID = $user->id;    
    $cachedUsersIDs = $cache->get('loggedInUserIDs');// array OR null
    if(is_array($cachedUsersIDs) && isset($cachedUsersIDs[$userID])) $duplicateLogIn = true;
    return $duplicateLogIn;
}

/**
 * Create or update cache for logged in user.
 *
 * @param User $user The user whose cache to set.
 * @return void
 * 
 */
function setLoggedInUserCache(User $user) {
    
    $cache = wire('cache');
    $userID = $user->id; 

    $cachedUsersIDs = $cache->get('loggedInUserIDs');
    // cache does not exist, create empty array ready to cache
    if(!count($cachedUsersIDs) || is_null($cachedUsersIDs)) $cachedUsersIDs = array();

    // save/update cache
    // for value, can use whatever, even $user->name; doesn't matter, key is the important thing here 
    // outer array: we use $user->id to group same user;
    // in inner array, we use session_id() to ensure uniqueness when removing cache
    $cachedUsersIDs[$userID][session_id()] = $userID;
    $cachedUsersIDsStr = json_encode($cachedUsersIDs);// JSON to save as cache
    $cache->save('loggedInUserIDs',$cachedUsersIDsStr);// @note: set expiration of cache if you wish to
    
}

/**
 * Remove a logged out user's cache.
 * 
 * This to allow subsequent logins.
 *
 * @param HookEvent $event The object (Session::logout) we are hooking into.
 * @return void
 * 
 */
function removeLoggedIn(HookEvent $event) {
    $user = wire('user');
    removeLoggedInUserCache($user);
    /* @note: for testing only
     $log = wire('log');
    $log->save("user-logs","Successful logout for '$user->name'"); */
}

/**
 * Remove the cache for a user who has logged out.
 *
 * @param User $user The user whose logged-in cache we are removing.
 * @return void
 * 
 */
function removeLoggedInUserCache(User $user) {

    $cache = wire('cache');
    $userID = $user->id;   
    
    $cachedUsersIDs = $cache->get('loggedInUserIDs');

    // cache does not exist/empty, nothing to do
    if(!count($cachedUsersIDs) || is_null($cachedUsersIDs)) return;      

    // save/update cache
    // @note: we check for current logged in user but we remove the whole user group (outer array)
    // this is because the user logged in 'validly' is logging out.
    if(isset($cachedUsersIDs[$userID][session_id()])) unset($cachedUsersIDs[$userID]);   
    $cachedUsersIDsStr = json_encode($cachedUsersIDs);
    // save updated cached
    $cache->save('loggedInUserIDs',$cachedUsersIDsStr);// @note: set expiration of cache if you wish to

}

 

Edited by kongondo
  • Like 4
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...