Files
dockerfluxodecaixapro/modules/auth/classes/Middleware/AuthMiddleware.php
T
2026-09-01 10:46:29 -03:00

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();
}
}
}