Jump to content
benbyf

restrict same user session

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?

Share this post


Link to post
Share on other sites

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? 

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
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.

Share this post


Link to post
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 3

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By neonwired
      I'm hoping someone has seen this before. There doesn't appear to be an issue with the user info.

       

    • By Greg Lumley
      Hi! I've just discovered Processwire and I'm absolutely loving how clean it is. Especially with the full control over what it outputs. 
      Excuse me if this is a really stupid question.
      What happens if a user wants to insert multiple images into the blog field? In other words Shift+Click all the images attached to a specific page in and insert. It seems I can insert one at a time but not multiple.

      Based on the above, I want to rebuild my website. I'm a photographer (ex php dev 2004) and plan also to target websites at other photographers. So inserting multiple images into blog posts is a key part. I'd like to output that to something like UIkit or some kind of Masonry Gallery script. Any thoughts would be fantastic please. 
      Thank you.
      Greg. 
      I'm an ex PHP developer now photographer, now thanks to Corona and not photo work, a rusty PHP developer 😁
    • By derelektrischemoench
      Hi guys,
      I'm facing a somewhat strange issue here which I can't quite wrap my head around. 
      I have a PW site in development which runs on three machines simultaneously, one staging server which is accessible as a preview instance for my customer, my PC and my laptop. 
      I have three completely identical settings on each of the three machines (same apache version, same php version, same codebase, same database); however on my PC I am unable to log into the backend. I get no error message or anything, when I try to login; i just get redirected to the login  page. I have already enabled database driven sessions (I enabled them on my laptop, then I dumped the database and copied it to my pc); I have cleared the cache directory; I cleared the sessions in the database; I cleared my browser caches, I tried different browsers, all to no avail; I am unable to login when using my pc, the instances all have the same .htaccess.
      Is there something I'm missing here or does anyone have a clue as to what my issue here might be? I'm using processwire 3.0.123
      Thanks for any input, greetings
      derelektrischemoench
       
      //edit: I've noticed something interesting; despite the directories of my web folders being the same layout; when I open the admin page i get a 404 on the processwire/ resource in the networks panel of chrome; on my laptop I get a  200.... I guess this is where my problem is; but why?
       
       
    • By derelektrischemoench
      Hi guys,
      I'm facing a somewhat strange issue here which I can't quite wrap my head around. 
      I have a PW site in development which runs on three machines simultaneously, one staging server which is accessible as a preview instance for my customer, my PC and my laptop. 
      I have three completely identical settings on each of the three machines (same apache version, same php version, same codebase, same database); however on my PC I am unable to log into the backend. I get no error message or anything, when I try to login; i just get redirected to the login  page. I have already enabled database driven sessions (I enabled them on my laptop, then I dumped the database and copied it to my pc); I have cleared the cache directory; I cleared the sessions in the database; I cleared my browser caches, I tried different browsers, all to no avail; I am unable to login when using my pc, the instances all have the same .htaccess.
      Is there something I'm missing here or does anyone have a clue as to what my issue here might be? I'm using processwire 3.0.123
      Thanks for any input, greetings
      derelektrischemoench
       
       
    • By Peter Knight
      How do you guys handle large session tables when sessions are being recorded to the database?
      I notice one of my sites has a session table of over 14MB 
      Am I missing a way in the Admin or a module to auto-remove any sessions older than X days?
      Thanks
       
×
×
  • Create New...