Laravel /broadcasting/auth 始终返回 403 错误

30

最近我开始研究Laravel 5.3的Laravel-Echo和Pusher组合。我已经成功设置了公共频道并转向了私有频道。但是在尝试授权操作时(包括使用简单的return true语句),我遇到了Laravel从/broadcasting/auth路由返回403的问题。有人能告诉我我做错了什么吗?

App/Providers/BroadcastServiceProvider.php:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes();

        /*
         * Authenticate the user's personal channel...
         */
        Broadcast::channel('App.User.*', function ($user, $userId) {
            return true;
        });
    }
}

资源/资产/js/bootstrap.js:

import Echo from "laravel-echo"

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'My-Key-Here'
});

window.Echo.private('App.User.1')
    .notification((notification) => {
        console.log(notification.type);
    });

我可以在Pusher的调试控制台中看到事件和其负载,但是一旦它到达auth路由就会失败。

12个回答

37

如果您使用 Laravel 版本 > 5.3 和 Pusher,访问 /broadcasting/auth 时出现错误 403,您需要修改 resources/assets/js/bootstrap.js 中的代码:

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'your key',
    cluster: 'your cluster',
    encrypted: true,
    auth: {
        headers: {
            Authorization: 'Bearer ' + YourTokenLogin
        },
    },
});

在app/Providers/BroadcastServiceProvider.php文件中,将原先的代码替换成:

Broadcast::routes()

使用

Broadcast::routes(['middleware' => ['auth:api']]);
或者
Broadcast::routes(['middleware' => ['jwt.auth']]); //if you use JWT
或者
Broadcast::routes(['middleware' => ['auth:sanctum']]); //if you use Laravel 

这对我有用,希望它对你也有帮助。


20
仅当您使用API令牌时,此内容才相关。 - Mostafa Attia
我在使用护照身份验证时遇到了同样的问题,我只是使用了授权令牌。现在它已经解决了。 - Syamlal
1
自从我使用 Sanctum 之后,我必须使用 Broadcast::routes(['middleware' => ['auth:sanctum']]);。所以这真的取决于您使用的身份验证类型!但是还是要感谢让我走上了正确的方向 :) 这里有关于该主题的更多信息:https://laravel.com/docs/8.x/broadcasting#authorizing-channels - Arno van Oordt

14

你链接的文档中说通道方法应该包括一个回调函数,该函数返回true或false,那么为什么你要返回$user呢? - Don't Panic
@Don'tPanic 因为对于 presence 频道,你应该返回有关用户的信息,而不是布尔值。 - Mikel Granero
@MikelGranero 谢谢,我现在明白了授权出席频道部分的描述。OP的问题是关于私人频道的,据我所知并不涉及出席频道,所以我不确定这个回答有多大帮助,但我学到了一些东西 :-) - Don't Panic

8

我将socket.io与redis配对使用,但是遇到了403错误的问题,尽管在/broadcasting/auth路由上没有任何身份验证中间件。仅在laracasts lesson观看后,我才意识到仅仅进行频道授权是不够的,始终应该有用户存在,无论您如何进行身份验证和获取用户,使用默认的laravel auth或某些令牌算法-jwt或其他任何方法。

已认证的用户会自动解析并作为第一个参数传递到routes/channels.php文件中的闭包函数中,因此您可以检查当前登录用户的频道可用性 enter image description here


1
谢谢您的回答。但是如果我使用自己的Auth中间件,我该如何将已经授权的用户传递给闭包函数呢? - Armalong
答案不是解决方案。我正在使用 sanctum 并将其用于 Auth::routes(),但仍然出现错误。 - Md. A. Apu

4

检查您如何授权您的频道。根据您的设置,这可能会有所帮助。使用以下内容更新BroadcastServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes(['middleware' => ['auth:api']]);

        require base_path('routes/channels.php');
    }
}

为Laravel Passport添加Auth API中间件。


1
这给了我一个302(已找到)状态 :/ - Mikel Granero

4

2
在我的情况下,问题是错误的用户ID:
Echo.private('user.'+CURRENT_USER_ID_HERE)

1
你救了我 :). 谢谢。 - Cloud

1

我遇到了相同的错误

/broadcasting/auth 403 (禁止)

我刚刚注意到我的项目/routes/channels中包含

Broadcast::channel('App.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

但是我的用户模型位于 Project/app/Models/User.php

所以我将 Project/routes/channels.php 更改为

Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

/broadcasting/auth 403 (Forbidden) 已修复

如果您的基本URL与http://localhost/broadcasting/auth不同,您可以在Echo初始化中定义authEndpoint

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    forceTLS: true,
    authEndpoint : `http://localhost/project/public/broadcasting/auth`,
});

请确保在 project/config/app.php 文件中取消注释此代码段。
App\Providers\BroadcastServiceProvider::class

如果要监听私有频道事件,您需要在JavaScript中定义Echo,如下所示:

Echo.private(`App.Models.User.{{ Auth::user()->id }}`)
.listen(".Illuminate\\Notifications\\Events\\BroadcastNotificationCreated",(notification) => {
      console.log('Got event...');
    });

你的 项目\app\Notifications\SendNotification.php 应该长这样

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\BroadcastMessage;

class SendNotification extends Notification implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct()
    {
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['broadcast'];
    }
 

    public function toBroadcast($notifiable)
    {
        return new BroadcastMessage([
            'message' => 'Hola!'
        ]);
    }
}

在您的用户模型中也可以使用Notifiable

在您的控制器中,您可以这样调用

$user->notify(new SendNotification());

您可以在Pusher仪表板的调试控制台上进行调试,下面是如果成功订阅的屏幕截图。 输入图像描述

您可以使用Pusher Debug Console测试事件,下面是屏幕截图 输入图像描述 希望这能帮到您。


这对我来说很有效!我正在使用惯性+Vue.js,并使用通知+广播,而不是事件。谢谢! - undefined

0

如果您已经退出登录,就会出现这种情况。确保您实际上已经登录到Laravel应用程序中,并且您当前的会话没有过期。

我重新登录后,它对我起作用了。


0
对我来说,403错误是由于JWT刷新的空通道名称引起的。由于某种原因,Axios发送了Content-Type: text/plain;charset=UTF-8,导致空的$request->channel_name。我明确设置了头部。
    window.Pusher = require('pusher-js/with-encryption');
    window.Echo = new Echo({
      broadcaster: 'pusher',
      key: key,
      host: host,
      cluster: 'us3',
      forceTLS: true,
      authorizer: (channel) => {
        return {
          authorize: (socketId, callback) => {
//HERE header needed
            const options = { headers: { 'Content-Type': 'application/json' } };
            const data = {
              socket_id: socketId,
              channel_name: channel.name,
            };
            apiChatAxios
              .post(`/broadcasting/auth`, data, options)
              .then((response) => {
                callback(false, response.data);
              })
              .catch((error) => {
                callback(true, error);
              });
          },
        };
      },
    });
``

0
如果有人在最新的Laravel 5.7中遇到相同的问题,对我有效的好解决方案是在每个频道返回之前或返回时检查身份验证,如下所示。
Broadcast::channel('user.*', function ($user) {
    return Auth::check();
});

Broadcast::channel('conversation.{id}', function ($user, $conversationId) {
    Auth::check();
    return $user->isInConversation(Conversation::find($conversationId));
});

这样就可以处理包括用户在内的任何频道广播的任何事件。

我希望它能帮助其他人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接