一起來實現單使用者登入 —— 訊息推送

MArtian發表於2021-12-13

一起來實現單使用者登入 —— 訊息推送

傳送實時訊息

接下來我們來實現當某個使用者的賬號在其他地方登入時,傳送一個實時訊息給當前的登入使用者,告訴他的賬號在其他裝置登入了。
後端元件: 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,所以列印到了日誌中。

下一節我們來完成前端實時顯示通知。

本作品採用《CC 協議》,轉載必須註明作者和本文連結
我從未見過一個早起、勤奮、謹慎,誠實的人抱怨命運。

相關文章