Laravel会话超时自动更新用户在线状态的实现方案
需求描述
无论浏览器是否处于打开状态,都需要在会话过期时执行特定操作。在我的Laravel项目中,用户登录时数据库会将其在线状态标记为1,退出时标记为0;我希望会话过期时,无需用户刷新页面,自动将状态更新为0,即使用户未注销直接关闭浏览器,也能在会话过期时标记为离线。
解决方案
我通过分析Laravel会话文件的结构,针对不同场景实现了需求:
场景1:用户登录后无操作超时
当用户登录后15分钟未进行任何操作时,自动跳转至登出路由并返回登录页。我通过JavaScript实现该功能,在所有页面的基础blade模板中添加以下代码:
... <body> ... <form id="logoutForm" method="POST" action="{{ route('logout') }}"> @csrf <!-- Token CSRF --> </form> ... </body> ... <script type="text/javascript"> // 闲置用户自动登出并重定向到登录页脚本 // 设置闲置超时时间(毫秒) var inactivityTimeout = 15 * 60 * 1000; // 15分钟 // 存储最后一次用户交互时间 var lastInteractionTime = new Date().getTime(); // 检查闲置状态,超时则执行登出 function checkInactivity() { var currentTime = new Date().getTime(); var elapsedTime = currentTime - lastInteractionTime; if (elapsedTime >= inactivityTimeout) { $('#logoutForm').submit(); } } // 更新最后一次交互时间 function updateLastInteractionTime() { lastInteractionTime = new Date().getTime(); } // 监听用户交互事件(移动鼠标、按键、点击) $(document).on('mousemove keydown click', updateLastInteractionTime); // 每秒检查一次闲置状态 setInterval(checkInactivity, 1000); </script>
场景2:用户未注销直接关闭浏览器
根据config/session.php和.env中的配置,用户未注销关闭浏览器后,会话仍会保持1小时活跃:
config/session.php
'lifetime' => env('SESSION_LIFETIME', 60), 'expire_on_close' => false,
.env
SESSION_LIFETIME=60
为了终止这类会话,我创建了Laravel命令UserSessionCleanup:
执行命令:php artisan make:command UserSessionCleanup
在生成的/app/Console/Commands/UserSessionCleanup.php文件中编写如下脚本:
<?php namespace App\Console\Commands; use App\Models\User; use Illuminate\Console\Command; use Illuminate\Support\Facades\Schema; class UserSessionCleanup extends Command { /** * 命令名称与签名 * * @var string */ protected $signature = 'UserSessionCleanup'; /** * 命令描述 * * @var string */ protected $description = "管理用户会话,将过期会话用户的在线状态更新为离线,并删除过期会话文件"; /** * 执行命令 * * @return int */ public function handle() { $sessionPath = storage_path('framework/sessions'); $allSessions = []; if (is_dir($sessionPath)) { $sessionFiles = scandir($sessionPath); // 步骤1:收集所有会话信息 foreach ($sessionFiles as $file) { if ($file !== '.' && $file !== '..') { $filePath = $sessionPath . '/' . $file; $fileContent = file_get_contents($filePath); $pattern = '/"login_web_[a-f0-9]+";i:(\d+)/'; preg_match($pattern, $fileContent, $matches); if (!empty($matches)) { $userId = $matches[1]; $creationTime = filectime($filePath); $formattedTime = date('Y-m-d H:i:s', $creationTime); $allSessions[] = [ 'user_id' => $userId, 'date_file' => $formattedTime, 'file_name' => $file, ]; } } } // 步骤2:筛选每个用户的最新会话 $latestSessions = []; foreach ($allSessions as $session) { $userId = $session['user_id']; if (!isset($latestSessions[$userId]) || $session['date_file'] > $latestSessions[$userId]['date_file']) { $latestSessions[$userId] = $session; } } // 步骤3:筛选创建时间超过15分钟的会话 $filteredSessions = []; foreach ($latestSessions as $session) { $creationTimestamp = strtotime($session['date_file']); $currentTimestamp = time(); $timeDifference = $currentTimestamp - $creationTimestamp; if ($timeDifference > (15 * 60)) { // 15分钟(秒数) $filteredSessions[] = $session; } } $i = 0; if (!empty($filteredSessions)) { // 步骤4:更新用户表中的在线状态 $userIdsToUpdate = array_column($filteredSessions, 'user_id'); if (Schema::hasTable('users')) { foreach ($userIdsToUpdate as $userId) { $userOnline = User::find($userId); if ($userOnline) { $userOnline->status_online = 0; $userOnline->save(); $i++; } } } else { echo "用户表不存在。\n"; } // 步骤5:删除筛选出的会话文件 foreach ($filteredSessions as $session) { $filePath = $sessionPath . '/' . $session['file_name']; if (file_exists($filePath)) { unlink($filePath); } } } echo "处理的过期会话数量:$i\n"; } else { echo "会话目录不存在。\n"; } return 0; } }
该脚本会检查超过15分钟未更新的已登录用户会话,将对应用户的在线状态更新为0并删除会话文件。
随后在/app/Console/Kernel.php中配置该命令每17分钟执行一次:
/** * 定义应用的命令调度 * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ protected function schedule(Schedule $schedule) { ... $schedule->command('UserSessionCleanup')->cron('*/17 * * * *'); // ->appendOutputTo('/app/storage/logs/scheduler.log'); ... }
场景3:用户活跃交互
当用户登录后持续与系统交互(点击、移动鼠标等),不会触发断开操作。
选择15分钟超时是为了符合PCI DSS 12.3.8的要求。
该方案虽非完美,但可满足需求。
内容的提问来源于stack exchange,提问作者Luizzz
相关产品推荐
相关产品推荐

