一起来实现单用户登录 —— 功能实现

一起来实现单用户登录 —— 功能实现

保证一个账号只有一个用户登录#

用户在访问网站时,会与网站建立 Session,并将 SessionId 存储在 Cookie,以此作为用户此次会话的凭证。

单用户登录的原理是:在用户登录后,销毁 这个用户之前所有与网站 通信时建立的 Session

下面我们来一起实现吧!


打开 .env 文件,我们将 SESSION_DRIVER 修改为 databse,这样做的好处是可以沉淀每次与用户的会话做数据分析,用户地区分布,用户访问设备等客户端信息。最直白的作用就是可以通过这些用户的失效 session 分析用户登录地址,看看哪些用户在分享账号。

...
SESSION_DRIVER=database // 修改为 database
SESSION_LIFETIME=120
...

假设你已经配置好了数据库,我们既然要将 session 存储在数据库,那么还需要建立一个 sessions 表, Laravel 已经非常贴心的为我们准备好了。

执行命令:

php artisan session:table

Laravel 已经为我们生成了迁移文件,我们直接执行迁移命令来创建数据表就好

php artisan migrate

用户登录#

下面我们来完成用户登录功能,执行命令来创建脚手架

php artisan ui:auth

访问 your-project-url/register 创建一个用户,并登录。

一起来实现单用户登录2


我们打开数据库中的 session

一起来实现单用户登录2

这条记录就是我们刚刚与网站建立的 Session

id user_id ip_address user_agent payload last_activity
服务端 Session 关联的 user 表 ID 访问地址 终端设备 前端加密的 SessionID 最后活跃时间

销毁之前的 Session#

我们已经生成了用户脚手架,打开 app/Http/Controllers/Auth/LoginController.php 文件。
Laravel 的登录功能依赖于 AuthenticatesUsers Trait。

// LoginController.php
class LoginController extends Controller
{
...
  use AuthenticatesUsers; // 打开这个 trait
...

我们来打开这个文件看看,往下找到 authenticated 方法

/**
* The user has been authenticated.
* 
* @param  \Illuminate\Http\Request $request
* @param  mixed  $user
* @return mixed
*/
protected function authenticated(Request $request, $user)
{
//
}

这个方法的触发节点是 用户授权成功之后,写入 Session 之前,那我们可以通过它来销毁已登录用户之前的所有 Session

把它复制一下,然后回到 LoginController 文件,将 authenticated 方法覆写成我们自己的业务逻辑。

protected function authenticated(Request $request, $user)
{
    DB::table('sessions')->where('user_id', $user->id)->delete()
}

我们可以简单粗暴的直接将用户之前登录 Session 删除,但是这样做并没有收集到用户信息,建立 Session 表就没意义了。

其实只需要将 session 表存储的 id 进行修改,使其与前端传输的 SessionID 不匹配,就代表会话失效,所以我们稍微修改一下

protected function authenticated(Request $request, $user)
{
    DB::table('sessions')->where('user_id', $user->id)
    ->update([
        'id' => DB::raw("concat('OUTMAN_', user_id, '_', id)"),
        'user_id' => null,
    ]);
}

id 添加 OUTMAN 前缀,并拼接 user_id 字段,这样既达到了 Session 失效,又保留了用户信息。


你可能会疑问,既然我们只更新数据,那为什么不直接使用 软删除 呢?

其实 sessions 表不只存储已登录用户的 session,在用户访问网站那一刻,就已经建立了 session,如果用户没有登录,那么这条记录其实对我们来讲其实没有意义。


回到浏览器,打开一个 窗口A,再使用快捷键 Ctrl+Shift+N 创建一个无痕 窗口B,达到 Session 隔离的目的。

先在 窗口A 登录账号,再到 窗口B 登录相同的账号,然后再回到 窗口A,按 F5 刷新一下页面,发现 窗口A 的用户已经退出。说明我们刚刚的代码生效了,因为在 窗口B 登录的时候,执行了查询,并把 窗口A 的 session 更新了。


我们再来看一下 sessions 表,已经有一个失效的 Session 了。

一起来实现单用户登录2

单用户登录功能已经实现,后面我们会给添加 websocket 通信,来实时通知用户。

本作品采用《CC 协议》,转载必须注明作者和本文链接
悲观者永远正确,乐观者永远前行。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 5

系列已读完,但有个问题。

id 添加 OUTMAN 前缀,并拼接 user_id 字段,这样既达到了 Session 失效,又保留了用户信息。

这里说要保留用户信息,采用修改而不是删除,但后文并没有地方用到这些信息。

保留这些失效 session 的目的什么?

3年前 评论
MArtian (楼主) 3年前
MArtian (楼主) 3年前
lddtime (作者) 3年前

楼主有没有试过多个 guard 情况

3年前 评论