mirror of
https://github.com/delight-im/PHP-Auth.git
synced 2025-08-07 08:36:28 +02:00
Regularly resynchronize session data with authoritative source in DB
This commit is contained in:
48
src/Auth.php
48
src/Auth.php
@@ -28,6 +28,8 @@ final class Auth extends UserManager {
|
|||||||
private $ipAddress;
|
private $ipAddress;
|
||||||
/** @var bool whether throttling should be enabled (e.g. in production) or disabled (e.g. during development) */
|
/** @var bool whether throttling should be enabled (e.g. in production) or disabled (e.g. during development) */
|
||||||
private $throttling;
|
private $throttling;
|
||||||
|
/** @var int the interval in seconds after which to resynchronize the session data with its authoritative source in the database */
|
||||||
|
private $sessionResyncInterval;
|
||||||
/** @var string the name of the cookie used for the 'remember me' feature */
|
/** @var string the name of the cookie used for the 'remember me' feature */
|
||||||
private $rememberCookieName;
|
private $rememberCookieName;
|
||||||
|
|
||||||
@@ -36,18 +38,21 @@ final class Auth extends UserManager {
|
|||||||
* @param string $ipAddress the IP address that should be used instead of the default setting (if any), e.g. when behind a proxy
|
* @param string $ipAddress the IP address that should be used instead of the default setting (if any), e.g. when behind a proxy
|
||||||
* @param string|null $dbTablePrefix (optional) the prefix for the names of all database tables used by this component
|
* @param string|null $dbTablePrefix (optional) the prefix for the names of all database tables used by this component
|
||||||
* @param bool|null $throttling (optional) whether throttling should be enabled (e.g. in production) or disabled (e.g. during development)
|
* @param bool|null $throttling (optional) whether throttling should be enabled (e.g. in production) or disabled (e.g. during development)
|
||||||
|
* @param int|null $sessionResyncInterval (optional) the interval in seconds after which to resynchronize the session data with its authoritative source in the database
|
||||||
*/
|
*/
|
||||||
public function __construct($databaseConnection, $ipAddress = null, $dbTablePrefix = null, $throttling = null) {
|
public function __construct($databaseConnection, $ipAddress = null, $dbTablePrefix = null, $throttling = null, $sessionResyncInterval = null) {
|
||||||
parent::__construct($databaseConnection, $dbTablePrefix);
|
parent::__construct($databaseConnection, $dbTablePrefix);
|
||||||
|
|
||||||
$this->ipAddress = !empty($ipAddress) ? $ipAddress : (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null);
|
$this->ipAddress = !empty($ipAddress) ? $ipAddress : (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null);
|
||||||
$this->throttling = isset($throttling) ? (bool) $throttling : true;
|
$this->throttling = isset($throttling) ? (bool) $throttling : true;
|
||||||
|
$this->sessionResyncInterval = isset($sessionResyncInterval) ? ((int) $sessionResyncInterval) : (60 * 5);
|
||||||
$this->rememberCookieName = self::createRememberCookieName();
|
$this->rememberCookieName = self::createRememberCookieName();
|
||||||
|
|
||||||
$this->initSession();
|
$this->initSession();
|
||||||
$this->enhanceHttpSecurity();
|
$this->enhanceHttpSecurity();
|
||||||
|
|
||||||
$this->processRememberDirective();
|
$this->processRememberDirective();
|
||||||
|
$this->resyncSessionIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initializes the session and sets the correct configuration */
|
/** Initializes the session and sets the correct configuration */
|
||||||
@@ -136,6 +141,46 @@ final class Auth extends UserManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function resyncSessionIfNecessary() {
|
||||||
|
// if the user is signed in
|
||||||
|
if ($this->isLoggedIn()) {
|
||||||
|
if (!isset($_SESSION[self::SESSION_FIELD_LAST_RESYNC])) {
|
||||||
|
$_SESSION[self::SESSION_FIELD_LAST_RESYNC] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's time for resynchronization
|
||||||
|
if (($_SESSION[self::SESSION_FIELD_LAST_RESYNC] + $this->sessionResyncInterval) <= \time()) {
|
||||||
|
// fetch the authoritative data from the database again
|
||||||
|
try {
|
||||||
|
$authoritativeData = $this->db->selectRow(
|
||||||
|
'SELECT email, username, status, roles_mask FROM ' . $this->dbTablePrefix . 'users WHERE id = ?',
|
||||||
|
[ $this->getUserId() ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Error $e) {
|
||||||
|
throw new DatabaseError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the user's data has been found
|
||||||
|
if (!empty($authoritativeData)) {
|
||||||
|
// update the session data
|
||||||
|
$_SESSION[self::SESSION_FIELD_EMAIL] = $authoritativeData['email'];
|
||||||
|
$_SESSION[self::SESSION_FIELD_USERNAME] = $authoritativeData['username'];
|
||||||
|
$_SESSION[self::SESSION_FIELD_STATUS] = (int) $authoritativeData['status'];
|
||||||
|
$_SESSION[self::SESSION_FIELD_ROLES] = (int) $authoritativeData['roles_mask'];
|
||||||
|
}
|
||||||
|
// if no data has been found for the user
|
||||||
|
else {
|
||||||
|
// their account may have been deleted so they should be signed out
|
||||||
|
$this->logOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember that we've just performed resynchronization
|
||||||
|
$_SESSION[self::SESSION_FIELD_LAST_RESYNC] = \time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to sign up a user
|
* Attempts to sign up a user
|
||||||
*
|
*
|
||||||
@@ -343,6 +388,7 @@ final class Auth extends UserManager {
|
|||||||
unset($_SESSION[self::SESSION_FIELD_STATUS]);
|
unset($_SESSION[self::SESSION_FIELD_STATUS]);
|
||||||
unset($_SESSION[self::SESSION_FIELD_ROLES]);
|
unset($_SESSION[self::SESSION_FIELD_ROLES]);
|
||||||
unset($_SESSION[self::SESSION_FIELD_REMEMBERED]);
|
unset($_SESSION[self::SESSION_FIELD_REMEMBERED]);
|
||||||
|
unset($_SESSION[self::SESSION_FIELD_LAST_RESYNC]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,6 +38,8 @@ abstract class UserManager {
|
|||||||
const SESSION_FIELD_ROLES = 'auth_roles';
|
const SESSION_FIELD_ROLES = 'auth_roles';
|
||||||
/** @var string session field for whether the user who is currently signed in (if any) has been remembered (instead of them having authenticated actively) */
|
/** @var string session field for whether the user who is currently signed in (if any) has been remembered (instead of them having authenticated actively) */
|
||||||
const SESSION_FIELD_REMEMBERED = 'auth_remembered';
|
const SESSION_FIELD_REMEMBERED = 'auth_remembered';
|
||||||
|
/** @var string session field for the UNIX timestamp in seconds of the session data's last resynchronization with its authoritative source in the database */
|
||||||
|
const SESSION_FIELD_LAST_RESYNC = 'auth_last_resync';
|
||||||
|
|
||||||
/** @var PdoDatabase the database connection to operate on */
|
/** @var PdoDatabase the database connection to operate on */
|
||||||
protected $db;
|
protected $db;
|
||||||
@@ -205,6 +207,7 @@ abstract class UserManager {
|
|||||||
$_SESSION[self::SESSION_FIELD_STATUS] = (int) $status;
|
$_SESSION[self::SESSION_FIELD_STATUS] = (int) $status;
|
||||||
$_SESSION[self::SESSION_FIELD_ROLES] = (int) $roles;
|
$_SESSION[self::SESSION_FIELD_ROLES] = (int) $roles;
|
||||||
$_SESSION[self::SESSION_FIELD_REMEMBERED] = $remembered;
|
$_SESSION[self::SESSION_FIELD_REMEMBERED] = $remembered;
|
||||||
|
$_SESSION[self::SESSION_FIELD_LAST_RESYNC] = \time();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user