First Commit
This commit is contained in:
+187
@@ -0,0 +1,187 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user