无法使用 Laravel echo server、redis 和 socket.io 验证 laravel 私人频道

Posted

技术标签:

【中文标题】无法使用 Laravel echo server、redis 和 socket.io 验证 laravel 私人频道【英文标题】:Unable to authenticate laravel private channel using Laravel echo server, redis and socket.io 【发布时间】:2020-07-28 04:16:36 【问题描述】:

我正在使用 Laravel Echo 服务器、redis 和 socket.io 来处理聊天消息。

我正在使用广播事件。

event(new MessageSent($messageThread));

这是私有频道,方法brodcastOn如下:

   public function broadcastOn()
    
        return new PrivateChannel('message.' . $this->broadcastUser->id);
    

我的routes/channels.php 看起来像:

Broadcast::channel('message.*', function ($user, $id) 
    return (int) $user->id === (int) $id;
);

下面是我的laravel-echo-server.json


    "authHost": "http://localhost:8000",
    "authEndpoint": "/broadcasting/auth",
    "clients": [
        
            "appId": "******",
            "key": "*************"
        
    ],
    "database": "redis",
    "databaseConfig": 
        "redis": 
            "port":"6379",
            "host":"127.0.0.1",
            "db":"0",
            "password":"****"
        
    ,
    "devMode": true,
    "host": null,
    "port": "6001",
    "protocol": "http",
    "socketio": ,
    "secureOptions": 67108864,
    "sslCertPath": "",
    "sslKeyPath": "",
    "sslCertChainPath": "",
    "sslPassphrase": "",
    "subscribers": 
        "http": true,
        "redis": true
    

用于监听事件的jQuery:

window.Echo = new Echo(
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001',
    client: socketio,
    auth: headers: 
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr("content"),
        ,
);

var userId = window.APP.user;

const channel = window.Echo.channel(`app_database_private-message.$userId`);

channel.listen('MessageSent', (payload) => 
   console.log('payload', payload)
);

这是来自config/database.php的我的redis部分:

'redis' => [

        'client' => env('REDIS_CLIENT', 'predis'),

        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'predis'),
            'prefix' => Str::slug(env('APP_NAME', 'laravel'), '_').'_database_',
        ],

        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => env('REDIS_DB', 0),
        ],

        'cache' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => env('REDIS_CACHE_DB', 1),
        ],

    ],

显示如下错误:

L A R A V E L  E C H O  S E R V E R

version 1.6.0

⚠ Starting server in DEV mode...

✔  Running at localhost on port 6001
✔  Channels are ready.
✔  Listening for http events...
✔  Listening for redis events...

Server ready!

[1:21:22 PM] - Preparing authentication request to: http://localhost:8000
[1:21:22 PM] - Sending auth request to: http://localhost:8000/broadcasting/auth

⚠ [1:21:22 PM] - IQ7eT9P_RzF62lRSAAAA could not be authenticated to app_database_private-message.3
         "message": "", "exception": "Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException", "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php", "line": 81, "trace": [  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php", "line": 58, "function": "verifyUserCanAccessChannel", "class": "Illuminate\\Broadcasting\\Broadcasters\\Broadcaster", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastManager.php", "line": 319, "function": "auth", "class": "Illuminate\\Broadcasting\\Broadcasters\\RedisBroadcaster", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php", "line": 237, "function": "__call", "class": "Illuminate\\Broadcasting\\BroadcastManager", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastController.php", "line": 23, "function": "__callStatic", "class": "Illuminate\\Support\\Facades\\Facade", "type": "::" ,  "function": "authenticate", "class": "Illuminate\\Broadcasting\\BroadcastController", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Controller.php", "line": 54, "function": "call_user_func_array" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php", "line": 45, "function": "callAction", "class": "Illuminate\\Routing\\Controller", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Route.php", "line": 219, "function": "dispatch", "class": "Illuminate\\Routing\\ControllerDispatcher", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Route.php", "line": 176, "function": "runController", "class": "Illuminate\\Routing\\Route", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Router.php", "line": 680, "function": "run", "class": "Illuminate\\Routing\\Route", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php", "line": 30, "function": "Illuminate\\Routing\\closure", "class": "Illuminate\\Routing\\Router", "type": "->" ,  "file": "/opt/edugem/apps/project/app/Http/Middleware/AppMiddleware.php", "line": 55, "function": "Illuminate\\Routing\\closure", "class": "Illuminate\\Routing\\Pipeline", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 163, "function": "handle", "class": "App\\Http\\Middleware\\AppMiddleware", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php", "line": 53, "function": "Illuminate\\Pipeline\\closure", "class": "Illuminate\\Pipeline\\Pipeline", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php", "line": 41, "function": "Illuminate\\Routing\\closure", "class": "Illuminate\\Routing\\Pipeline", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 163, "function": "handle", "class": "Illuminate\\Routing\\Middleware\\SubstituteBindings", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php", "line": 53, "function": "Illuminate\\Pipeline\\closure", "class": "Illuminate\\Pipeline\\Pipeline", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php", "line": 75, "function": "Illuminate\\Routing\\closure", "class": "Illuminate\\Routing\\Pipeline", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 163, "function": "handle", "class": "Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php", "line": 53, "function": "Illuminate\\Pipeline\\closure", "class": "Illuminate\\Pipeline\\Pipeline", "type": "->" ,  "file": "/opt/edugem/apps/project/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php", "line": 49, "function": "Illuminate\\Routing\\closure"

【问题讨论】:

【参考方案1】:

您有 2 个问题:

在 Echo 方面,您应该使用
window.Echo.private(`message.$userId`);

您还必须确保将 Laravel 配置变量 database.redis.options.prefix 设置为 ''

在 Laravel 方面,您需要实现通道的授权,以允许套接字侦听此私有通道。
Broadcast::channel('message.userId', function ($user, $userId) 
    //Your authorization logic which should return a boolean
);

https://laravel.com/docs/7.x/broadcasting#defining-authorization-callbacks

【讨论】:

我已经在 channels.php 文件中使用了Broadcase::channel('message.userId'...。我已经更新了我的问题。但它仍然无法正常工作。 您需要在您的授权通道中指定id 而不是* 以便从回调中检索它。 我已经做到了。现在它没有抛出那个错误。但它没有使用console.log(payload) 记录有效负载。 请从您的config/database.php 文件中显示您的redis 部分 正如我在回答中所说,您需要将prefix 设置为'',它应该可以工作【参考方案2】:

而不是

channel.listen('MessageSent', (payload) => 
   console.log('payload', payload)
);

使用此语句

channel.listen('.MessageSent', (payload) => 
   console.log('payload', payload)
);

在 Echo 中的命名空间前使用点(.)

例子

window.Echo(...)
.listen('.namespace')

并在通知类中重写broadcastAs 并使用shouldBroadCastNow

broadcastAs()
return 'namespace'

【讨论】:

以上是关于无法使用 Laravel echo server、redis 和 socket.io 验证 laravel 私人频道的主要内容,如果未能解决你的问题,请参考以下文章

laravel-echo-server 用户未加入,未订阅套接字服务器

laravel-echo-server 404 尝试进行身份验证时

使用 Laravel Echo、laravel-echo-server 和 socket.io 广播将不起作用

Laravel 事件广播没有被拾取 laravel-echo-server

Laravel Echo - 允许访客连接到出席频道

Laravel-echo-server 码头化问题