Laravel 实现单用户登录

需求:同一时间只能有一个人登录账号,后登录者会把前登录者顶下线
参考:https://laravel-china.org/articles/2929/laravel-single-user-login
 https://segmentfault.com/a/1190000007906164

关键思路:登录时制作一个token(根据id,ip,time),保存在session和redis中,在检查登录的中间件加一个token检验,如果token对不上说明有第二个人在另一个地方登录导致token被改变了,旧的登录者auth::logout(),重定向到登录页面

(原本参考laravel-china的文章使用响应后面添加withCookie来存token,后面想到cookie在浏览器关闭后会被删除,于是使用session)

关键代码:

在登录事件监听handle写一个制作发送token的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public function handle(LoginEvent $event) {
$this->sendCookieToken($member, $request);
}

/*
* 制作token,用于单用户登录验证
*/
public function sendCookieToken(Authenticatable $member, Request $request) {
$time = time();
$sinleToken = md5($request->getClientIp().$member->id.$time);
\Redis::set($member->id, $time);
$request->session()->put('SINGLETOKEN', $sinleToken);
}

检查登录中间件进行验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public function handle($request, Closure $next, $guard = null) {

if (!Auth::guard('web')->check()) {
if ($request->ajax() || $request->header('ajax') == 1) {
$return = [
'code' => ResultCode::CODE_NOT_LOGIN,
'message' => '请登录!',
'extra' => [],
];
return response()->json($return);
} else {
return redirect('/login');
}
}
if ($this->isRelogin($request)) {
\Auth::guard('web')->logout();
return redirect('/login');
}

return $next($request);
}

/*
* 比较token,判断是否需要重新登录
*/
protected function isRelogin($request) {
$member = Auth::user();
if ($member) {
// 获取 session 中的 token
$singletoken = $request->session()->get('SINGLETOKEN');
if ($singletoken) {
// 从 redis 获取 time
$redisTime = \Redis::get($member->id);
// 重新获取加密参数加密
$ip = $request->getClientIp();
$secret = md5($ip . $member->id . $redisTime);
if ($singletoken !== $secret) {
return true;
}
return false;
}
}
return false;
}

当然路由还需根据自己项目来设置