一起来实现单用户登录 —— 消息推送

Laravel框架
562
0
0
2022-08-06
标签   消息推送

一起来实现单用户登录 —— 消息推送

发送实时消息

接下来我们来实现当某个用户的账号在其他地方登录时,发送一个实时消息给当前的登录用户,告诉他的账号在其他设备登录了。

后端组件: laravel-websocketspusher

我们开始吧!


先来完成后端的功能,打开 .env 文件

PUSHER_APP_ID=123123
PUSHER_APP_KEY=321321
PUSHER_APP_SECRET=secret
PUSHER_APP_CLUSTER=mt1

这些是 pusher 的配置,随意填写,只需要保证和前端的 laravel-echo 一致即可。如果一台服务器上有多个站点,需要保证 id 和 key 的唯一性。


安装组件

laravel-websocets 依赖 guzzlehttp/psr7 组件的 1.5 版本,但是它的最新版本已经到 2.1,而 guzzlehttp 也依赖它,并且要求最低是 1.8 两者相冲突了,所以不能直接使用 composer require 命令安装。

同样,pusher 也需要使用 3.0 版本。

打开 composer.json

"require": {
        ...
        "guzzlehttp/psr7": "^1.5",
        "beyondcode/laravel-websockets": "^1.12.0",
        "pusher/pusher-php-server": "~3.0"
    },

我们直接把这两个组件粘贴进去,然后执行命令:

composer update

发布 laravel-websockets

php artisan vendor:publish 

在列表里选择 BeyondCode\LaravelWebSockets\WebSocketsServiceProvider 对应的序号。

一起来实现单用户登录3

Laravel 框架的消息推送功能默认使用的是 pusher 第三方 API 服务,我们使用 laravel-websocket 来拦截 pusher 发出的请求,转发到我们自己的服务器。


配置 websocket

关于 websockets 的配置,可以在 config/websockets.php 里找到

官方文档:点击这里

你只需要知道它在哪里即可,我们没有需要定制的配置。

然后打开 config/broadcasting.php,修改 pusher 发送的请求地址为我们本地 ip 地址。

'connections' => [ 
        'pusher' => [
            ...
            'options' => [
                'cluster' => env('PUSHER_APP_CLUSTER'),
                'encrypted' => true,
                'host' => '127.0.0.1',
                'port' => 6001,
                'scheme' => 'http'
            ],
        ],

好了,组件安装完成,执行命令启动 websocket 服务

php artisan websockets:serve

打开 your-project/laravel-websockets 可以看到控制台,点击 Connect 可以看到所有的发送消息明细。

一起来实现单用户登录3

推送消息

我们来创建一个事件,在每次用户登录成功后触发,执行命令:

php artisan make:event UserAuthenticatedEvent

还记得上一节提到的 authenticated 方法吗?我们在这个方法里面来触发事件:

public 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
    ]);
    // 触发广播事件,发送一个消息给之前的登录用户  
    broadcast(new UserAuthenticatedEvent($user))->toOthers();
}

既然是广播事件,那就需要实现广播的接口,打开 UserAuthenticatedEvent.php

<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; 
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserAuthenticatedEvent implements ShouldBroadcast
{
  use Dispatchable, InteractsWithSockets, SerializesModels;

  public $user;

  public function __construct(User $user)
  {  
      $this->user = $user;
  } 

  public function broadcastOn()
  { 
      // 发送频道拼接 user_id,避免干扰  
    return new Channel('outman-user-'. $this->user->id);
  }
}

再回到首页开 A,B 窗口登录,然后查看 storage/logs/laravel.log

[2021-12-13 13:34:43] local.INFO: Broadcasting [App\Events\UserAuthenticatedEvent] on channels [outman-user-1] with payload:
{
    "user": {
        "id": 1,
        "name": "ricky",
        "email": "ricky@me.com",
        "email_verified_at": null,
        "created_at": "2021-12-12T14:03:00.000000Z",
        "updated_at": "2021-12-12T14:03:00.000000Z"
    },
    "socket": null
}

消息已经发出了,因为我们现在的 BROADCAST_DRIVER 还是 log,所以打印到了日志中。

下一节我们来完成前端实时显示通知。