mirror of
https://github.com/processwire/processwire.git
synced 2025-08-13 10:15:28 +02:00
Add @kixe PR #94 which adds a "disallow parallel sessions" option to SessionHandlerDB. When enabled, only one login can be maintained at a time per user.
This commit is contained in:
@@ -5,9 +5,14 @@
|
|||||||
*
|
*
|
||||||
* @see /wire/core/SessionHandler.php
|
* @see /wire/core/SessionHandler.php
|
||||||
*
|
*
|
||||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
* ProcessWire 3.x, Copyright 2018 by Ryan Cramer
|
||||||
* https://processwire.com
|
* https://processwire.com
|
||||||
*
|
*
|
||||||
|
* @property int|bool $useIP Track IP address?
|
||||||
|
* @property int|bool $useUA Track user agent?
|
||||||
|
* @property int|bool $noPS Prevent more than one session per logged-in user?
|
||||||
|
* @property int $lockSeconds Max number of seconds to wait to obtain DB row lock.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class SessionHandlerDB extends WireSessionHandler implements Module, ConfigurableModule {
|
class SessionHandlerDB extends WireSessionHandler implements Module, ConfigurableModule {
|
||||||
@@ -41,7 +46,8 @@ class SessionHandlerDB extends WireSessionHandler implements Module, Configurabl
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->database = $this->wire('database');
|
$this->database = $this->wire('database');
|
||||||
$this->set('useIP', 0); // track IP address?
|
$this->set('useIP', 0); // track IP address?
|
||||||
$this->set('useUA', 0); // track query string?
|
$this->set('useUA', 0); // track user agent?
|
||||||
|
$this->set('noPS', 0); // disallow parallel sessions per user
|
||||||
$this->set('lockSeconds', 50); // max number of seconds to wait to obtain DB row lock
|
$this->set('lockSeconds', 50); // max number of seconds to wait to obtain DB row lock
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +55,7 @@ class SessionHandlerDB extends WireSessionHandler implements Module, Configurabl
|
|||||||
parent::init();
|
parent::init();
|
||||||
// keeps session active
|
// keeps session active
|
||||||
$this->wire('session')->set($this, 'ts', time());
|
$this->wire('session')->set($this, 'ts', time());
|
||||||
|
if($this->noPS) $this->addHookAfter('Session::loginSuccess', $this, 'hookLoginSuccess');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -238,6 +245,15 @@ class SessionHandlerDB extends WireSessionHandler implements Module, Configurabl
|
|||||||
$f->description = $description;
|
$f->description = $description;
|
||||||
$form->add($f);
|
$form->add($f);
|
||||||
|
|
||||||
|
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||||
|
$f->attr('name', 'noPS');
|
||||||
|
$f->attr('value', 1);
|
||||||
|
$f->attr('checked', empty($data['noPS']) ? '' : 'checked');
|
||||||
|
$f->label = $this->_('Disallow parallel sessions?');
|
||||||
|
$f->notes = $this->_('When enabled, successful login expires all other sessions for that user on other devices/browsers.');
|
||||||
|
$f->description = $this->_('Checking this box will allow only one single session for a logged-in user at a time.');
|
||||||
|
$form->add($f);
|
||||||
|
|
||||||
if(ini_get('session.gc_probability') == 0) {
|
if(ini_get('session.gc_probability') == 0) {
|
||||||
$form->warning(
|
$form->warning(
|
||||||
"Your PHP has a configuration error with regard to sessions. It is configured to never clean up old session files. " .
|
"Your PHP has a configuration error with regard to sessions. It is configured to never clean up old session files. " .
|
||||||
@@ -374,4 +390,27 @@ class SessionHandlerDB extends WireSessionHandler implements Module, Configurabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook called after Session::loginSuccess to enforce the noPS option
|
||||||
|
*
|
||||||
|
* @param HookEvent $event
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function hookLoginSuccess(HookEvent $event) {
|
||||||
|
if(!$this->noPS) return;
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $event->arguments(0);
|
||||||
|
$table = self::dbTableName;
|
||||||
|
$query = $this->wire('database')->prepare("DELETE FROM `$table` WHERE user_id=:user_id AND id!=:id");
|
||||||
|
$query->bindValue(':id', session_id());
|
||||||
|
$query->bindValue(':user_id', $user->id, \PDO::PARAM_INT);
|
||||||
|
$query->execute();
|
||||||
|
$n = $query->rowCount();
|
||||||
|
if($n) $this->message(sprintf(
|
||||||
|
$this->_('Previous login session for “%s” has been removed/logged-out.'),
|
||||||
|
$user->name
|
||||||
|
));
|
||||||
|
$query->closeCursor();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user