187 lines
5.5 KiB
PHP
Executable File
187 lines
5.5 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Modules\Auth\Middleware;
|
|
|
|
use Closure;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
use Modules\Auth\Models\User;
|
|
use Kernel\Application;
|
|
|
|
class AuthMiddleware
|
|
{
|
|
/**
|
|
* Handle an incoming request.
|
|
*
|
|
* @param Request $request
|
|
* @param Closure $next
|
|
* @return mixed
|
|
*/
|
|
public function handle(Request $request, Closure $next)
|
|
{
|
|
// Check if user is authenticated
|
|
if (!$this->isAuthenticated()) {
|
|
if ($this->expectsJson($request)) {
|
|
return new JsonResponse([
|
|
'success' => false,
|
|
'message' => __('auth.unauthenticated'),
|
|
'timestamp' => time()
|
|
], 401);
|
|
}
|
|
|
|
// Redirect to login page for web requests
|
|
return new Response('', 302, [
|
|
'Location' => url('/login')
|
|
]);
|
|
}
|
|
|
|
// Check if user session is still valid
|
|
if (!$this->isSessionValid()) {
|
|
$this->logout();
|
|
|
|
if ($this->expectsJson($request)) {
|
|
return new JsonResponse([
|
|
'success' => false,
|
|
'message' => __('auth.session_expired'),
|
|
'timestamp' => time()
|
|
], 401);
|
|
}
|
|
|
|
return new Response('', 302, [
|
|
'Location' => url('/login?expired=1')
|
|
]);
|
|
}
|
|
|
|
// Set user in request for easy access
|
|
$request->attributes->set('user', $this->getCurrentUser());
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
/**
|
|
* Check if user is authenticated.
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function isAuthenticated(): bool
|
|
{
|
|
if (isset($_SESSION['user_id']) && !empty($_SESSION['user_id'])) {
|
|
return true;
|
|
}
|
|
if (!empty($_COOKIE['remember_token'])) {
|
|
$secret = $_ENV['APP_KEY'] ?? '';
|
|
$parts = explode(':', $_COOKIE['remember_token']);
|
|
if (count($parts) === 3) {
|
|
[$id, $token, $sig] = $parts;
|
|
$payload = $id . ':' . $token;
|
|
$expected = hash_hmac('sha256', $payload, $secret);
|
|
if (hash_equals($expected, $sig)) {
|
|
try {
|
|
$user = User::find((int)$id);
|
|
if ($user && $user->users_remember_token === $token) {
|
|
$_SESSION['user_id'] = $user->users_id;
|
|
$_SESSION['user_idbus'] = $user->users_bus_id;
|
|
$_SESSION['user_role'] = $user->users_role;
|
|
$_SESSION['last_activity'] = time();
|
|
return true;
|
|
}
|
|
} catch (\Throwable $e) {}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if session is still valid.
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function isSessionValid(): bool
|
|
{
|
|
if (!isset($_SESSION['last_activity'])) {
|
|
return false;
|
|
}
|
|
|
|
$timeoutSetting = 120;
|
|
try {
|
|
if (class_exists('\App\Models\Module')) {
|
|
$module = \App\Models\Module::byName('auth')->first();
|
|
if ($module) {
|
|
$timeoutSetting = (int)($module->getSetting('session_timeout', 120));
|
|
}
|
|
}
|
|
} catch (\Throwable $e) {}
|
|
$sessionTimeout = (int)($_ENV['SESSION_LIFETIME'] ?? $timeoutSetting) * 60;
|
|
$lastActivity = $_SESSION['last_activity'];
|
|
$currentTime = time();
|
|
|
|
// Check if session has expired
|
|
if (($currentTime - $lastActivity) > $sessionTimeout) {
|
|
return false;
|
|
}
|
|
|
|
// Update last activity time
|
|
$_SESSION['last_activity'] = $currentTime;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get current authenticated user.
|
|
*
|
|
* @return User|null
|
|
*/
|
|
protected function getCurrentUser(): ?User
|
|
{
|
|
if (!$this->isAuthenticated()) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return User::find($_SESSION['user_id']);
|
|
} catch (\Exception $e) {
|
|
// Log error and invalidate session
|
|
error_log("Error loading user: " . $e->getMessage());
|
|
$this->logout();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if request expects JSON response.
|
|
*
|
|
* @param Request $request
|
|
* @return bool
|
|
*/
|
|
protected function expectsJson(Request $request): bool
|
|
{
|
|
return $request->headers->get('Accept') === 'application/json' ||
|
|
$request->headers->get('Content-Type') === 'application/json' ||
|
|
str_contains($request->getPathInfo(), '/api/');
|
|
}
|
|
|
|
/**
|
|
* Logout user and destroy session.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function logout(): void
|
|
{
|
|
// Unset all session variables
|
|
unset($_SESSION['user_id']);
|
|
unset($_SESSION['user_idbus']);
|
|
unset($_SESSION['user_role']);
|
|
unset($_SESSION['last_activity']);
|
|
unset($_SESSION['csrf_token']);
|
|
|
|
// Destroy session
|
|
session_destroy();
|
|
|
|
// Start new session for possible flash messages
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
}
|
|
} |