Laravel 5.2 - How to logout a user from all of his

2019-02-07 00:42发布

When a user logged out from a perticular device I want to logout from all the device he has logged in till now . How I do it in Laravel.

I have used Redis for keeping the userId in Session by installing "predis/predis": "~1.0"

And Here is my controller for SignIn and 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');
}

It's successfully get logged in and also logged out but it doesn't kill all the session in other devices.

How do I solve the problem?

2条回答
家丑人穷心不美
2楼-- · 2019-02-07 00:49

I have a suggestion/workaround for Your problem:

Working with sessions which are not stored in database is pain in a**, so You have to think differently in order to solve the problem. The different solution would be to record user id and time, when user logout. Then create middleware which will disconnects user if connection is older than last logout date. And thats all.


My prototype would look like so:
In postSignIn method line below will record user (session) login date: app('request')->session()->put('login_date', time());

In getLogout method line below will record user logout date globally: \Cache::put('last_logout_'.\Auth::id(), time());

And final touch would be middleware with code similar to this:

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...
    }
}

Full code:

Methods:

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

Middleware:

<?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楼-- · 2019-02-07 00:56

So issue was with typo in redis key name, for write data used $redis->sadd('users:sessions:'.$userId,Session::getId()); where key's prefix 'users:sessions:' and for get data used $redis->srem('user:sessions:' . $userId, $sessionId); where key's prefix 'user:sessions:' Thats why code didn't work and dd() returned empty array.

so correct code looks like this

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');
}
查看更多
登录 后发表回答