Initial commit
This commit is contained in:
175
app/Http/Middleware/CheckProfileInactivity.php
Normal file
175
app/Http/Middleware/CheckProfileInactivity.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Config; // Import Config facade
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
||||
|
||||
class CheckProfileInactivity
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
// Only proceed if a user is authenticated
|
||||
if (!Auth::check()) {
|
||||
Session::forget('last_activity'); // Clear timestamp if user logs out
|
||||
return $next($request); // Pass the request to the next middleware - route-level auth middleware will handle redirect
|
||||
}
|
||||
|
||||
// When user is authenticated
|
||||
$activeProfileType = Session::get('activeProfileType', \App\Models\User::class); // Default to User class if not set
|
||||
|
||||
// Initialize active profile if not set (happens after login)
|
||||
if (!Session::has('activeProfileId')) {
|
||||
$user = Auth::guard('web')->user();
|
||||
if ($user) {
|
||||
Session::put([
|
||||
'activeProfileType' => \App\Models\User::class,
|
||||
'activeProfileId' => $user->id,
|
||||
'activeProfileName' => $user->name,
|
||||
'activeProfilePhoto' => $user->profile_photo_path,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$lastActivity = Session::get('last_activity');
|
||||
|
||||
// If last_activity is not set, initialize it and continue (first request after login)
|
||||
if (!$lastActivity) {
|
||||
Session::put('last_activity', now());
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
// Check base session timeout first (this should never exceed SESSION_LIFETIME)
|
||||
// This prevents profile-specific timeouts from keeping sessions alive beyond the base session lifetime
|
||||
$baseSessionLifetime = Config::get('session.lifetime', 120); // minutes
|
||||
$minutesSinceActivity = now()->diffInMinutes($lastActivity);
|
||||
|
||||
// If base session has expired, force logout regardless of profile type
|
||||
if ($minutesSinceActivity >= $baseSessionLifetime) {
|
||||
$user = Auth::guard('web')->user();
|
||||
Auth::guard('web')->logout();
|
||||
Session::invalidate();
|
||||
Session::regenerateToken();
|
||||
|
||||
// For AJAX requests, return a JSON response indicating logout
|
||||
if ($request->expectsJson() || $request->ajax()) {
|
||||
return response()->json([
|
||||
'message' => __('Your session timed out due to inactivity. Please log in again.'),
|
||||
'action' => 'logout',
|
||||
'redirect_url' => LaravelLocalization::localizeUrl('/login')
|
||||
], 419); // 419 Authentication Timeout
|
||||
} else {
|
||||
// For standard browser requests, redirect to login
|
||||
$loginUrl = LaravelLocalization::localizeUrl('/login');
|
||||
return redirect()->to($loginUrl)
|
||||
->with('warning', __('Your session timed out due to inactivity. Please log in again.'));
|
||||
}
|
||||
}
|
||||
|
||||
// Get the specific timeout for the current profile type, or use the default of 120 min.
|
||||
$configuredTimeout = timebank_config('profile_timeouts.' . $activeProfileType, timebank_config('profile_timeout_default', 120));
|
||||
|
||||
// Profile-specific timeout cannot exceed base session lifetime
|
||||
// This ensures elevated profiles timeout at or before the base session expiration
|
||||
$timeoutMinutes = min($configuredTimeout, $baseSessionLifetime);
|
||||
|
||||
// Log when timeout is being capped for debugging purposes
|
||||
if ($configuredTimeout > $baseSessionLifetime) {
|
||||
\Log::info('Profile timeout capped by SESSION_LIFETIME', [
|
||||
'profile_type' => class_basename($activeProfileType),
|
||||
'configured_timeout' => $configuredTimeout,
|
||||
'session_lifetime' => $baseSessionLifetime,
|
||||
'effective_timeout' => $timeoutMinutes,
|
||||
]);
|
||||
}
|
||||
|
||||
// Check if the timestamp exists and if the inactivity period has passed
|
||||
if ($minutesSinceActivity >= $timeoutMinutes) {
|
||||
$user = Auth::guard('web')->user();
|
||||
|
||||
// Check if the current active profile is already the User profile
|
||||
if ($activeProfileType === \App\Models\User::class) {
|
||||
// If the active profile is User and their session expires, log them out
|
||||
Auth::guard('web')->logout();
|
||||
Session::invalidate();
|
||||
Session::regenerateToken();
|
||||
|
||||
// For AJAX requests, return a JSON response indicating logout
|
||||
if ($request->expectsJson() || $request->ajax()) {
|
||||
return response()->json([
|
||||
'message' => __('Your session timed out due to inactivity. Please log in again.'),
|
||||
'action' => 'logout', // Indicate a full logout
|
||||
'redirect_url' => LaravelLocalization::localizeUrl('/login') // Provide login URL
|
||||
], 419); // 419 Authentication Timeout
|
||||
} else {
|
||||
// For standard browser requests, redirect to login
|
||||
$loginUrl = LaravelLocalization::localizeUrl('/login');
|
||||
return redirect()->to($loginUrl)
|
||||
->with('warning', __('Your session timed out due to inactivity. Please log in again.'));
|
||||
}
|
||||
} else {
|
||||
// If the active profile is an elevated profile (Bank, Admin, etc.), switch back to User profile
|
||||
Session::put([
|
||||
'activeProfileType' => \App\Models\User::class,
|
||||
'activeProfileId' => $user->id,
|
||||
'activeProfileName' => $user->name,
|
||||
'activeProfilePhoto' => $user->profile_photo_path,
|
||||
'profile-switched-notification' => true,
|
||||
]);
|
||||
|
||||
session(['notification.alert' => 'Your previous profile session timed out due to inactivity.']); // Will become a translation key in notification component
|
||||
|
||||
Session::forget('last_activity'); // Clear the timestamp
|
||||
|
||||
event(new \App\Events\ProfileSwitchEvent($user));
|
||||
|
||||
// Check if the request expects JSON (common for AJAX) or is an AJAX request
|
||||
if ($request->expectsJson() || $request->ajax()) {
|
||||
session(['notification.alert' => 'Your previous profile session timed out due to inactivity.']); // Will become a translation key in notification component
|
||||
|
||||
// Get the user's locale from the session (set by localization middleware)
|
||||
$userLocale = Session::get('locale', config('app.fallback_locale'));
|
||||
// Use LaravelLocalization to get the full, localized URL
|
||||
$redirectUrl = LaravelLocalization::getURLFromRouteNameTranslated($userLocale, 'routes.main');
|
||||
Session::save();
|
||||
|
||||
// Return a JSON response indicating timeout, use 419 status code
|
||||
return response()->json([
|
||||
'message' => __('Your previous profile session timed out due to inactivity.'),
|
||||
'action' => 'redirect', // Change action name to 'redirect'
|
||||
'redirect_url' => $redirectUrl // <-- Add URL to payload
|
||||
], 419); // 419 Authentication Timeout
|
||||
} else {
|
||||
// For standard browser requests, perform the redirect with flash message
|
||||
$mainUrl = LaravelLocalization::localizeUrl('/main-page');
|
||||
return redirect()->to($mainUrl)
|
||||
->with('warning', __('Your previous profile session timed out due to inactivity.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the activity timestamp on relevant requests
|
||||
// Exclude background heartbeats but allow user-initiated Livewire interactions
|
||||
$isLivewireUpdate = $request->is(['*/livewire/update', 'livewire/update']);
|
||||
$isUserInteraction = $isLivewireUpdate && $request->has('components');
|
||||
|
||||
if (!$request->is(['api/messenger/heartbeat']) && (!$isLivewireUpdate || $isUserInteraction)) {
|
||||
Session::put('last_activity', now());
|
||||
}
|
||||
|
||||
return $next($request); // Ensure the request is passed to the next middleware
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user