Laravel 5.2 - 如何从他的所有设备中注销用户

时间:2016-05-24 06:15:41

标签: php laravel session redis laravel-5.2

当用户从特定设备注销时,我想从他登录的所有设备注销到现在为止。我是如何在Laravel中完成的。

我使用Redis通过安装“predis / predis”来保持userId在Session中:“~1.0”

这是我的SignIn和Logout控制器:

  public function postSignIn(Request $request)
    {       

       if (Auth::attempt(['email' => $request['email'], 'password' =>$request['password'] ]) ) {

       $redis = \Redis::connection();   
        $userId=Session::getId();
        $redis->sadd('users:sessions:'.$userId,Session::getId());
          return redirect()->route('main');

        }
        return redirect()->back();
    }



public function getLogout()
{
    $redis = Redis::connection();
    $userId=Session::getId();
    $userSessions = $redis->smembers('user:sessions:' . $userId);
    $currentSession = Session::getId();
    foreach ($userSessions as $sessionId) {
         if ($currentSession == $sessionId) {
      continue; 

            }
             $redis->srem('user:sessions:' . $userId, $sessionId);
            $redis->del('laravel:' . $sessionId);

        }
    Auth::logout();
    return redirect()->route('main');
}

它已成功登录并注销但不会终止其他设备中的所有会话。

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

我对您的问题有一个建议/解决方法:

使用未存储在数据库中的会话很痛苦,因此您必须以不同的方式思考才能解决问题。用户注销时,不同的解决方案是记录用户ID和时间。然后创建中间件,如果连接早于上次注销日期,将断开用户连接。这就是全部。

我的原型看起来像这样:
在下面的postSignIn方法行中,将记录用户(会话)登录日期:app('request')->session()->put('login_date', time());

在以下getLogout方法行中,将全局记录用户注销日期: \Cache::put('last_logout_'.\Auth::id(), time());

最后的触摸是中间件,其代码与此类似:

if ($user = \Auth::user()) {
    $login_date       = app('request')->session()->get('login_date');
    $last_logout_date = \Cache::get('last_logout_' . $user->id, time() + 100);
    if ($login_date < $last_logout_date) {
        \Auth::logout();
        //redirect, error message...
    }
}

完整代码:

方法:

public function postSignIn(Request $request)
{
    if (Auth::attempt(['email' => $request['email'], 'password' => $request['password']])) {
        app('request')->session()->put('login_date', time());

        return redirect()->route('main');
    }

    return redirect()->back();
}

public function getLogout()
{
    \Cache::put('last_logout_' . \Auth::id(), time());
    Auth::logout();

    return redirect()->route('main');
}

中间件:

<?php

namespace App\Http\Middleware;

use Closure;

class LogoutIfExpired
{
    public function handle($request, Closure $next, $guard = null)
    {
        if ($user = \Auth::user()) {
            $login_date       = app('request')->session()->get('login_date');
            $last_logout_date = \Cache::get('last_logout_' . $user->id, time() + 100);
            if ($login_date < $last_logout_date) {
                \Auth::logout();

                return redirect()->route('main');
            }
        }

        return $next($request);
    }
}

答案 1 :(得分:3)

所以问题是redis密钥名称中的拼写错误, 用于写入数据 $redis->sadd('users:sessions:'.$userId,Session::getId()); 其中键的前缀为'users:sessions:',用于获取数据 $redis->srem('user:sessions:' . $userId, $sessionId);其中键的前缀'user:sessions:' 这就是为什么代码没有工作,dd()返回空数组。

所以正确的代码看起来像这样

public function postSignIn(Request $request)
{    

   if (Auth::attempt(['email' => $request['email'], 'password' =>$request['password'] ]) ) {
        $redis = \Redis::connection();   
        $userId=Session::getId();
        $redis->sadd('user:sessions:'.$userId,Session::getId());
        return redirect()->route('main');
    }
    return redirect()->back();
}



public function getLogout()
{
    $redis = Redis::connection();
    $userId=Session::getId();
    $userSessions = $redis->smembers('user:sessions:' . $userId);
    $currentSession = Session::getId();

    foreach ($userSessions as $sessionId) {
         if ($currentSession == $sessionId) {
             continue; 
         }
            $redis->srem('user:sessions:' . $userId, $sessionId);
            $redis->del('laravel:' . $sessionId);
        }
    Auth::logout();
    return redirect()->route('main');
}