You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 9如何限制终端用户仅在单设备同时登录

Laravel 9 限制单设备登录的解决方案

针对你遇到的同一用户多设备登录问题,以及旧会话未主动登出就不会过期的痛点,这里提供两种可靠的实现方案:

方案一:基于数据库会话的旧会话强制失效

这个方案利用Laravel的数据库会话存储,在用户新登录时直接清除该用户的所有旧会话,从根源上阻止多设备同时在线。

步骤1:配置数据库会话驱动

  1. 修改.env文件,将会话驱动改为数据库:
SESSION_DRIVER=database
  1. 生成会话表迁移文件并执行迁移:
php artisan session:table
php artisan migrate

步骤2:监听登录事件清除旧会话

  1. 创建登录事件监听器:
php artisan make:listener RevokeOldSessions --event=Illuminate\Auth\Events\Login
  1. 在生成的app/Listeners/RevokeOldSessions.php中编写处理逻辑:
<?php

namespace App\Listeners;

use Illuminate\Auth\Events\Login;
use Illuminate\Support\Facades\DB;

class RevokeOldSessions
{
    public function handle(Login $event)
    {
        // 删除当前用户除当前会话外的所有旧会话
        DB::table('sessions')
            ->where('user_id', $event->user->id)
            ->where('id', '!=', session()->getId())
            ->delete();
    }
}
  1. 在app/Providers/EventServiceProvider.php中注册监听器:
protected $listen = [
    \Illuminate\Auth\Events\Login::class => [
        \App\Listeners\RevokeOldSessions::class,
    ],
];

补充:自动清理过期会话

Laravel会自动清理过期会话,但可以通过任务调度确保定时执行:
在app/Console/Kernel.php的schedule方法中添加:

$schedule->command('session:gc')->hourly();

方案二:基于活跃会话ID的请求校验

这个方案通过在用户表存储当前活跃会话ID,搭配中间件实时校验请求会话是否为用户的唯一活跃会话,旧设备的请求会被强制登出。

步骤1:给用户表添加活跃会话ID字段

  1. 生成迁移文件:
php artisan make:migration add_active_session_id_to_users_table --table=users
  1. 编辑迁移文件:
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('active_session_id')->nullable();
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('active_session_id');
        });
    }
};
  1. 执行迁移:
php artisan migrate

步骤2:登录时更新活跃会话ID

在app/Http/Controllers/Auth/LoginController.php中添加authenticated方法:

protected function authenticated(Request $request, $user)
{
    // 将当前会话ID设为用户的活跃会话ID
    $user->update(['active_session_id' => session()->getId()]);
}

步骤3:创建校验中间件

  1. 生成中间件:
php artisan make:middleware CheckActiveSession
  1. 编辑中间件逻辑:
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class CheckActiveSession
{
    public function handle(Request $request, Closure $next)
    {
        // 已登录用户校验会话是否匹配活跃会话ID
        if (auth()->check() && auth()->user()->active_session_id !== session()->getId()) {
            auth()->logout();
            return redirect()->route('login')->with('error', '你的账号已在其他设备登录,请重新登录');
        }

        return $next($request);
    }
}
  1. 在app/Http/Kernel.php的web中间件组中注册该中间件:
protected $middlewareGroups = [
    'web' => [
        // ... 其他中间件
        \App\Http\Middleware\CheckActiveSession::class,
    ],
];

步骤4:登出时清空活跃会话ID

在app/Http/Controllers/Auth/LogoutController.php中添加loggedOut方法:

protected function loggedOut(Request $request)
{
    if (auth()->check()) {
        auth()->user()->update(['active_session_id' => null]);
    }
}

方案对比

  • 方案一:直接清除旧会话,逻辑简单,适合大多数web应用;需依赖数据库会话驱动,会自动处理会话过期。
  • 方案二:通过会话ID校验,更灵活,可自定义提示信息;中间件会在每次请求时校验,性能影响极小。

内容的提问来源于stack exchange,提问作者Umar Adil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 07:35:35