@@ -80,6 +80,12 @@ class Filters extends BaseConfig
|
||||
// Badge PDF generation posts (handled by auth; allow multiple submits without reload)
|
||||
'badge',
|
||||
'index.php/badge',
|
||||
|
||||
// Session keep-alive endpoint updates only the current browser session.
|
||||
'session/ping',
|
||||
'index.php/session/ping',
|
||||
'session/ping-activity',
|
||||
'index.php/session/ping-activity',
|
||||
]],
|
||||
],
|
||||
'after' => [
|
||||
|
||||
@@ -288,7 +288,9 @@ $routes->get('ui/style', 'View\UiController::style');
|
||||
|
||||
|
||||
//Timeout page after timeout
|
||||
$routes->get('session/get-timeout-config', 'View\SessionTimeoutController::getTimeoutConfig');
|
||||
$routes->get('session/check-timeout', 'View\SessionTimeoutController::checkTimeout');
|
||||
$routes->post('session/ping-activity', 'View\SessionTimeoutController::pingActivity');
|
||||
$routes->post('session/ping', 'View\SessionTimeoutController::pingActivity');
|
||||
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ namespace Config;
|
||||
|
||||
class SessionTimeout
|
||||
{
|
||||
// Session timeout in seconds (12 hours)
|
||||
public const TIMEOUT_DURATION = 43200;
|
||||
// Session timeout in seconds (30 minutes)
|
||||
public const TIMEOUT_DURATION = 1800;
|
||||
|
||||
// Warning threshold in seconds (5 minutes before timeout)
|
||||
public const WARNING_THRESHOLD = 42900;
|
||||
// Show warning after 25 minutes of inactivity (5 minutes before timeout)
|
||||
public const WARNING_THRESHOLD = 1500;
|
||||
|
||||
// Server-side check interval (in seconds)
|
||||
public const CHECK_INTERVAL = 300; // 5 minutes
|
||||
public const CHECK_INTERVAL = 60; // 1 minute
|
||||
|
||||
// Client-side check interval (in milliseconds)
|
||||
public const CLIENT_CHECK_INTERVAL = 60000; // 1 minute
|
||||
|
||||
@@ -559,6 +559,7 @@ class AuthController extends BaseController
|
||||
'user_type' => $user['user_type'],
|
||||
'is_logged_in' => true,
|
||||
'login_time' => time(),
|
||||
'last_activity' => time(),
|
||||
'roles' => $roleNames,
|
||||
'semester' => $this->semester,
|
||||
'school_year' => $this->schoolYear,
|
||||
|
||||
@@ -15,11 +15,11 @@ class SessionTimeoutController extends BaseController
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'timeout' => SessionTimeout::TIMEOUT_DURATION,
|
||||
'warning_time' => SessionTimeout::WARNING_THRESHOLD,
|
||||
'check_interval' => SessionTimeout::CHECK_INTERVAL,
|
||||
'logout_url' => site_url('auth/logout'),
|
||||
'keep_alive_url' => site_url('session/pingActivity'),
|
||||
'check_url' => site_url('session/checkTimeout')
|
||||
'warning_time' => SessionTimeout::TIMEOUT_DURATION - SessionTimeout::WARNING_THRESHOLD,
|
||||
'check_interval' => SessionTimeout::CLIENT_CHECK_INTERVAL,
|
||||
'logout_url' => site_url('logout'),
|
||||
'keep_alive_url' => site_url('session/ping-activity'),
|
||||
'check_url' => site_url('session/check-timeout')
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ class SessionTimeoutController extends BaseController
|
||||
$lastActivity = $session->get('last_activity');
|
||||
$elapsed = time() - $lastActivity;
|
||||
|
||||
if ($elapsed > SessionTimeout::TIMEOUT_DURATION) {
|
||||
if ($elapsed >= SessionTimeout::TIMEOUT_DURATION) {
|
||||
return $this->expireSession();
|
||||
} elseif ($elapsed > SessionTimeout::WARNING_THRESHOLD) {
|
||||
} elseif ($elapsed >= SessionTimeout::WARNING_THRESHOLD) {
|
||||
return $this->response->setJSON([
|
||||
'status' => 'warning',
|
||||
'time_remaining' => SessionTimeout::TIMEOUT_DURATION - $elapsed
|
||||
@@ -56,7 +56,7 @@ class SessionTimeoutController extends BaseController
|
||||
|
||||
// Only update if session is still valid
|
||||
if (!$session->has('last_activity') ||
|
||||
(time() - $session->get('last_activity') > SessionTimeout::TIMEOUT_DURATION)) {
|
||||
(time() - $session->get('last_activity') >= SessionTimeout::TIMEOUT_DURATION)) {
|
||||
return $this->expireSession();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,8 @@ class SessionTimeoutController extends BaseController
|
||||
$session->remove('last_activity');
|
||||
$session->destroy();
|
||||
|
||||
// Regenerate session ID for security
|
||||
session_regenerate_id(true);
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
session_regenerate_id(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Filters;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Filters\FilterInterface;
|
||||
use Config\SessionTimeout;
|
||||
|
||||
class AuthFilter implements FilterInterface
|
||||
{
|
||||
@@ -38,6 +39,7 @@ class AuthFilter implements FilterInterface
|
||||
$userRoles = $session->get('roles');
|
||||
$userId = $session->get('user_id');
|
||||
$loginTime = (int) $session->get('login_time');
|
||||
$lastActivity = (int) $session->get('last_activity');
|
||||
|
||||
// Must be logged in
|
||||
if (empty($userRoles) || empty($userId)) {
|
||||
@@ -55,6 +57,12 @@ class AuthFilter implements FilterInterface
|
||||
return $this->handleExpiredSession($request);
|
||||
}
|
||||
|
||||
if ($lastActivity <= 0 || (time() - $lastActivity) >= SessionTimeout::TIMEOUT_DURATION) {
|
||||
return $this->handleExpiredSession($request, 'Your session has expired due to inactivity. Please log in again.');
|
||||
}
|
||||
|
||||
$session->set('last_activity', time());
|
||||
|
||||
// Load role IDs for this user
|
||||
$roleIdRows = $this->db->table('user_roles')
|
||||
->select('role_id')
|
||||
@@ -83,7 +91,7 @@ class AuthFilter implements FilterInterface
|
||||
return $this->deny($request, "You don't have permission to use this feature.");
|
||||
}
|
||||
|
||||
private function handleExpiredSession(RequestInterface $request)
|
||||
private function handleExpiredSession(RequestInterface $request, string $message = 'Your session has expired. Please log in again.')
|
||||
{
|
||||
session()->destroy();
|
||||
|
||||
@@ -92,7 +100,7 @@ class AuthFilter implements FilterInterface
|
||||
->setStatusCode(401)
|
||||
->setJSON([
|
||||
'status' => 'expired',
|
||||
'message' => 'Your session has expired. Please log in again.',
|
||||
'message' => $message,
|
||||
'redirect' => '/login',
|
||||
]);
|
||||
}
|
||||
@@ -104,7 +112,7 @@ class AuthFilter implements FilterInterface
|
||||
}
|
||||
|
||||
return redirect()->to('/login?redirect_to=' . rawurlencode('/' . ltrim($target, '/')))
|
||||
->with('error', 'Your session has expired. Please log in again.');
|
||||
->with('error', $message);
|
||||
}
|
||||
|
||||
private function parseRequirements(?array $arguments): array
|
||||
|
||||
Reference in New Issue
Block a user