需求:同一时间只能有一个人登录账号,后登录者会把前登录者顶下线
参考: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
13public 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
44public 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;
}
当然路由还需根据自己项目来设置