Laravel 5.2 - Как выйти из системы пользователя со всех его устройств


Когда пользователь выходит из системы с пертикулярного устройства, я хочу выйти из всех устройств, на которых он входил до сих пор. Как я это делаю в Laravel.

Я использовал Redis для сохранения идентификатора пользователя в сеансе, установив "predis/predis": "~1.0"

А вот мой контроллер для входа и выхода из системы:

  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');
}

Он успешно вошел в систему, а также вышел из системы, но это не убивает весь сеанс на других устройствах.

Как мне решить эту проблему?

Author: Hola, 2016-05-24

2 answers

Таким образом, проблема заключалась в опечатке в имени ключа 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');
}
 3
Author: dyachenko, 2016-05-27 19:17:40

У меня есть предложение/обходной путь для Вашей проблемы:

Работа с сеансами, которые не хранятся в базе данных, - это боль в **, поэтому вам нужно думать по-другому, чтобы решить проблему. Другим решением было бы записать идентификатор пользователя и время выхода пользователя из системы. Затем создайте промежуточное программное обеспечение, которое отключит пользователя, если подключение старше даты последнего выхода из системы. И это все.


Мой прототип выглядел бы так:
В строке метода 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);
    }
}
 3
Author: Giedrius Kiršys, 2016-05-27 15:31:32