在Laravel中实现登录超时自动退出功能,可以通过以下两种方式实现(推荐使用复合方案):
方案一:会话生命周期控制(基础版)
核心配置 .env
:
SESSION_LIFETIME=30 # 会话有效期(分钟)
SESSION_EXPIRE_ON_CLOSE=true # 关闭浏览器即失效
验证中间件 app/Http/Middleware/CheckSessionTimeout.php
:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class CheckSessionTimeout
{
public function handle($request, Closure $next)
{
// 已登录用户检查最后活动时间
if (Auth::check()) {
$lastActive = session('last_active_time');
$timeout = config('session.lifetime') * 60; // 转换为秒
if (time() - $lastActive > $timeout) {
Auth::logout();
session()->flush();
return redirect('/login')->with('timeout', '会话已超时,请重新登录');
}
session(['last_active_time' => time()]); // 更新活动时间戳
}
return $next($request);
}
}
注册中间件 app/Http/Kernel.php
:
protected $routeMiddleware = [
// ...
'session.timeout' => \App\Http\Middleware\CheckSessionTimeout::class,
];
路由应用示例:
Route::group(['middleware' => ['auth', 'session.timeout']], function () {
// 需要登录的受保护路由
});
方案二:复合方案(会话+数据库验证)
扩展用户模型 app/Models/User.php
:
protected $dates = ['last_activity_at'];
public function checkActivityTimeout($minutes = 30)
{
return !$this->last_activity_at ||
$this->last_activity_at->diffInMinutes(now()) > $minutes;
}
活动追踪中间件 app/Http/Middleware/RecordUserActivity.php
:
public function handle($request, Closure $next)
{
if (Auth::check()) {
$user = Auth::user();
$user->last_activity_at = now();
$user->save();
}
return $next($request);
}
组合使用中间件:
// 在Kernel.php的web中间件组中添加:
\App\Http\Middleware\RecordUserActivity::class,
// 受保护路由组:
Route::group([
'middleware' => ['auth', 'session.timeout', 'check.activity:30']
], function() {
// 需要双重验证的路由
});
方案三:前端自动跳转(配合方案一/二)
JavaScript监听(Blade模板):
let idleTimer;
const timeoutMinutes = {{ config('session.lifetime') }};
const timeoutMs = timeoutMinutes * 60 * 1000;
function resetTimer() {
clearTimeout(idleTimer);
idleTimer = setTimeout(logout, timeoutMs);
}
function logout() {
window.location.href = '/login?timeout=1';
}
// 用户活动监听
document.addEventListener('mousemove', resetTimer);
document.addEventListener('keypress', resetTimer);
resetTimer(); // 初始启动
心跳路由(保持会话活跃):
// routes/web.php
Route::post('/keep-alive', function() {
return response()->json(['status' => 'active']);
});
// 前端每5分钟发送请求
setInterval(() => {
fetch('/keep-alive', { method: 'POST' });
}, 5 * 60 * 1000);
安全增强措施
- 并发登录控制:
// 修改Auth配置 config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
'hash' => false,
'expire' => env('SESSION_LIFETIME', 120), // 同步会话时间
],
],
- 密码修改后全局退出:
// 修改密码后调用
Auth::logoutOtherDevices($newPassword);
// 清除所有活动会话
DB::table('sessions')
->where('user_id', Auth::id())
->delete();
配置验证流程
- 测试超时场景:
# 临时设置1分钟超时(测试用)
SESSION_LIFETIME=1 php artisan serve
- 查看会话表(使用database驱动时):
SELECT * FROM sessions WHERE user_id = {userId}
实现效果说明
- 多层防御:会话超时+数据库活跃时间验证+前端自动跳转
- 精准控制:可针对不同用户组设置不同的超时时间
- 活动追踪:精确记录用户最后操作时间(精确到秒)
- 安全审计:通过
last_last_activity_at
字段可进行安全审计
注意:生产环境建议使用Redis作为会话驱动以获得最佳性能,同时需要确保服务器时间与客户端时间同步。