当用户从特定设备注销时,我想从他登录的所有设备注销到现在为止。我是如何在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');
}
它已成功登录并注销但不会终止其他设备中的所有会话。
我该如何解决这个问题?
答案 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');
}