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

Laravel中如何获取当前用户的所有登录会话(Redis驱动)

获取Redis驱动下特定用户的所有会话并实现多设备注销

核心思路

Laravel的Redis会话以键值对存储:键为带前缀的会话ID,值为序列化的会话数据。要定位特定用户的会话,要么从会话数据中识别用户ID,要么额外维护用户与会话的映射关系,两种方案分别适用于不同场景。


方法一:遍历解析会话数据(无需额外存储)

适合不想修改现有登录逻辑的场景,通过扫描Redis会话键,逐个解析数据匹配目标用户ID:

1. 确保会话中存储用户ID

如果登录时未主动存入,可在LoginController的authenticated方法中补充:

protected function authenticated(Request $request, $user)
{
    // 将用户ID存入会话,作为后续匹配标识
    $request->session()->put('user_id', $user->id);
}

2. 扫描并筛选目标用户的会话

使用SCAN命令(比KEYS更高效,避免阻塞Redis)遍历所有会话键,解析数据后筛选:

use Illuminate\Support\Facades\Redis;

$targetUserId = 123; // 要查询的目标用户ID
$sessionConn = Redis::connection('session');
$sessionPrefix = config('session.prefix', 'laravel:session');
$userSessions = [];

$iterator = null;
do {
    // 扫描匹配所有会话键
    [$iterator, $keys] = $sessionConn->scan($iterator, 'MATCH', "{$sessionPrefix}:*");
    
    if (!empty($keys)) {
        foreach ($keys as $key) {
            $sessionData = $sessionConn->get($key);
            if (!$sessionData) continue;
            
            // 反序列化Laravel会话数据
            $sessionPayload = unserialize($sessionData);
            
            // 匹配目标用户ID
            if (isset($sessionPayload['user_id']) && $sessionPayload['user_id'] === $targetUserId) {
                $userSessions[] = [
                    'session_key' => $key,
                    'remaining_ttl' => $sessionConn->ttl($key), // 会话剩余有效期
                    'user_agent' => $sessionPayload['HTTP_USER_AGENT'] ?? '未知设备' // 若存了用户代理可显示设备信息
                ];
            }
        }
    }
} while ($iterator > 0);

// $userSessions 即为该用户的所有会话列表

3. 注销指定设备

直接删除对应Redis会话键即可:

// 传入要注销的会话键
$sessionConn->del($targetSessionKey);

方法二:维护用户-会话映射集合(高效查询)

通过Redis集合存储每个用户的会话键,避免遍历所有会话,大幅提升查询效率:

1. 登录时添加会话到用户集合

在LoginController的authenticated方法中,将当前会话键加入用户专属集合:

protected function authenticated(Request $request, $user)
{
    $request->session()->put('user_id', $user->id);
    $sessionId = $request->session()->getId();
    $fullSessionKey = config('session.prefix', 'laravel:session') . ":{$sessionId}";
    
    // 将会话键存入用户的会话集合
    Redis::connection('session')->sadd("user:sessions:{$user->id}", $fullSessionKey);
}

2. 会话销毁时移除集合中的条目

监听SessionDestroyed事件,在会话过期或用户主动注销时,从集合中移除对应键:

  • 在EventServiceProvider中注册监听:
protected $listen = [
    \Illuminate\Session\Events\SessionDestroyed::class => [
        \App\Listeners\CleanUserSessionCollection::class,
    ],
];
  • 创建监听器CleanUserSessionCollection:
namespace App\Listeners;

use Illuminate\Session\Events\SessionDestroyed;
use Illuminate\Support\Facades\Redis;

class CleanUserSessionCollection
{
    public function handle(SessionDestroyed $event)
    {
        $sessionConn = Redis::connection('session');
        $sessionData = unserialize($sessionConn->get($event->sessionId));
        
        if (isset($sessionData['user_id'])) {
            // 从用户集合中移除失效的会话键
            $sessionConn->srem("user:sessions:{$sessionData['user_id']}", $event->sessionId);
        }
    }
}

3. 快速获取用户所有会话

直接读取用户集合即可:

$targetUserId = 123;
$userSessionKeys = Redis::connection('session')->smembers("user:sessions:{$targetUserId}");

// 可选:批量获取会话详情
$userSessions = [];
foreach ($userSessionKeys as $key) {
    if ($sessionData = Redis::connection('session')->get($key)) {
        $payload = unserialize($sessionData);
        $userSessions[] = [
            'session_key' => $key,
            'user_agent' => $payload['HTTP_USER_AGENT'] ?? '未知设备'
        ];
    }
}

4. 定期清理失效会话

Redis会自动删除过期会话,但集合中的条目不会同步移除,需定时任务清理:

// 示例:在Console/Kernel.php中添加每日定时任务
protected function schedule(Schedule $schedule)
{
    $schedule->call(function () {
        $sessionConn = Redis::connection('session');
        // 遍历所有用户会话集合(可按需限定用户范围)
        $collectionKeys = $sessionConn->keys("user:sessions:*");
        
        foreach ($collectionKeys as $key) {
            $sessionKeys = $sessionConn->smembers($key);
            foreach ($sessionKeys as $sessionKey) {
                if (!$sessionConn->exists($sessionKey)) {
                    $sessionConn->srem($key, $sessionKey);
                }
            }
        }
    })->daily();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:53:17