若我想让账户避免同时登录,该如何实现

我希望项目能够做到避免账户同时登录,不知道该如何实现,虚心指教

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 20

你要的是不是这个?

file

4年前 评论
Epona

什么叫避免重复登录,如果是登录过一次之后就不再输入密码的话, Laravel 已经自带 “记住我”的功能了。

4年前 评论
SZL_ (楼主) 4年前
Epona
4年前 评论
SZL_ (楼主) 4年前
Epona (作者) 4年前
Epona (作者) 4年前

你要的是不是这个?

file

4年前 评论

其实你说的就是唯一登陆,实现起来不难

4年前 评论
SZL_ (楼主) 4年前

那这个要怎么用@kangfq
file

4年前 评论

涉及概念:

  • 这里涉及到 『登录态』的概念,即对已登录的账号记录状态,标识已登录。

实现方案:

  • 对已经登录的账号,将状态存储到 Redis当中并设置有效期(例如:设置 30 分钟)。
  • 当这个账号再次登录的时候,先判断这个账号在 Redis 是否已经存在状态,如果存在则不让其登录。
  • 这种场景下还会涉及『踢登录态』的概念,例如:在另一个地方登录这个账号的时候,是否需要将已经登录的账号,踢掉?

总结:

  • 上面的实现方案只是个大概的,具体场景还得具体分析,但是这里涉及的『登录态』的概念是逃不掉的。
  • 以上纯属个人见解,不喜勿喷,欢迎撕逼。
4年前 评论
yema

简单点 用户名当键 登录时间戳为值 存起来 每次请求携带登陆时间戳,验证这个登陆时间戳是否和当前用户的登陆时间戳一样
(该方法比较原始,但思路比较明确,可能存有思考不当地方,可以自己加以修改)
'-------------------------------------------------------'分割线

比如user现在登陆了 ,缓存用redis。
那么redis::set('user','2019-08-29 10:54:00(你可以存时间戳)','3600(一小时)')。
然后session('user','2019-08-29 10:54:00(你可以存时间戳)')

比如现在user来请求了。那好,你通过user取得session和redis里的登陆时间,然后判断是否一致。
如果一致,那好,说明没有别人更新这个缓存,也就没人用user第二次登陆。
如果redis过期了,也就是一小时到了,此时session确还有效,在续命一个小时就可以了,如果session过期了,直接退出,清空redis缓存。

如果没过期情况下第二个人也用这个user登陆了,那么按照逻辑,
他也会session('user',''2019-08-29 11:24:00(你可以存时间戳)'),redis::set('user','2019-08-29 11:24:00(你可以存时间戳)','3600(一小时)'),此时redis的值被改变了。

按照redis是共享的,所以此时这个redis里的登陆时间就变掉了。那么第一个user过来请求,此时他的session里的登陆时间就和redis里的登陆时间不一样了。因为被第二个user更新了。

如果你不想让第二个人登陆,就在每次登陆时检查redis里是否存在这个user的缓存。
为了保证缓存利用性,要给缓存设置过期时间,和退出清空缓存,请求是发现session过期了,退出登陆时也要清空缓存。
然后上面也说了,缓存过期时间快过session过期,给缓存续命就好了,续命的前提是缓存不存在,而不是缓存存在但登陆时间不同。

4年前 评论
假如_丶 4年前
SZL_ (楼主) 4年前
Zhibin 4年前
yema (作者) 4年前
SZL_ (楼主) 4年前
yema (作者) 4年前
Su 4年前
yema (作者) 4年前
Su 4年前
yema (作者) 4年前

类似QQ挤下线操作吧, 当时是做的APP, 用的是设备号做唯一凭证

4年前 评论

看你应用的场景了,APP 的话保证 TOKEN 唯一,一端登录 TOKEN 改变,TOKEN 失效,PC 端基于SESSION 的话那就是 session 失效

4年前 评论
SZL_ (楼主) 4年前

避免同时登录的情况有两种

  • 踢下线

这种情况比较好处理,只要登录的时候重置下token,那么之前登录状态的账号就失效了

  • 提示当前账号已经登录,登录失败

这种情况下,你只要在用户表增加一个登录状态的字段,每次登录之前,判断这个字段是否为登录状态即可

4年前 评论

我的做法(apitoken 方式)
创建中间表模型
file
登录的时候调用createToken
所有请求中间件调用hasToken

4年前 评论
SZL_ (楼主) 4年前
wuyan94zl (作者) 4年前

简单方式:直接记录在cache()缓存中,以用户id为键,以到期时间为值,每次访问更新到期时间,有值说明已经登录过,没有值则是未登录

4年前 评论

最简单的方法是用户登录成功后把用户的sessionId储存到缓存中,然后再cookie中也存一份sessionId,用户访问的时候,比较这两个sessionId,如果不一样,那就踢下线

4年前 评论
SZL_ (楼主) 4年前
Code_Er

直接点 用token方式 如果当前请求接口的token跟uid不一样那么就是不是同一个人了

4年前 评论

我的实现原理:使用浏览器的 session id 来判断,每次用户登录后更新用户的session id,然后通过中间件来过滤,不知道是不是你想要的效果,这是 5.5 的版本,5.5 以上版本好像自带有这种功能。

中间件

  1. 新建 app/Http/Middleware/SingleDeviceLogin.php
<?php

namespace App\Http\Middleware;

use Closure;

class SingleDeviceLogin
{
    public function handle($request, Closure $next)
    {
        if (\Auth::check() && \Auth::user()->session_id != session()->getId()) {
            \Auth::logout();

            abort(422, '您已在别的设备登录');
        }

        return $next($request);
    }
}
  1. 加入到 app/Http/Kernel.php$middlewareGroupsweb
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\SingleDeviceLogin::class,
    ],
];

登录事件

  1. 新建 app/Listeners/LoginListener.php
<?php

namespace App\Listeners;

use Illuminate\Auth\Events\Login;
use Illuminate\Contracts\Queue\ShouldQueue;

class LoginListener implements ShouldQueue
{
    public function handle(Login $event)
    {
        $update = [
            'session_id' => session()->getId(),
        ];

        $event->user->update($update);
    }
}
  1. app/Providers/EventServiceProvider.php 注册监听事件
protected $listen = [
    'Illuminate\Auth\Events\Login' => [
        'App\Listeners\LoginListener'
    ],
];

至此,完成

4年前 评论
SZL_ (楼主) 4年前
SZL_ (楼主) 4年前

实现避免账户同时登录,核心就是用一张表记录用户会话信息。

用户会话表:会话ID、用户ID、登录状态(已登录、已退出)

当用户在新设备身份验证成功登录时,会产生新会话,登录状态为已登录;同时根据会话记录,将该用户历史的会话记录登录状态从已登录标记为已退出即可。
另一方面,用户登录态检查的中间件,要求登录状态为已登录。

4年前 评论

常见的无外乎两种场景。
1.基于cookie+session的用户认证
不管先后登陆成功--->都保存session_id(可以在用户表加一个字段保存or存在redis里)
中间件校验session_id和服务器保存的session_id是否一致。不一致(被挤掉了)销销毁该会话session跳转到登录页。
原理就是后者登录成功会把保存的session_id更新。
2.基于token的用户认证,后者登录成功直接重置token即可。

4年前 评论

登录成功后把密码重新bcrypt一下并更新到users表,然后把新加密好的密码存入session。

中间件验证登录的用户session里面的密码和users表里面的是否相同,如果不同的话就退出这个用户的登录,官方的好像也是这么实现的。

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!