Laravel Echo + веб-сокеты + частные каналы

Я знаю, что я не первый борюсь с этим. Но после нескольких дней, когда я задавал множество связанных вопросов, я почему-то чувствую, что мой случай заслуживает отдельного вопроса :).

У меня есть рабочие решения для веб-сокетов с Laravel Websockets (https://beyondco.de/docs/laravel-websockets/getting-started/introduction) и Laravel Echo для общедоступных каналов. Мое клиентское приложение представляет собой приложение vue-cli и подключается к серверу + широковещательные сообщения по общедоступным каналам отлично работают. Авторизация осуществляется Laravel Passport. Таким образом, отправляя токен-носитель в заголовке авторизации, серверное приложение знает, аутентифицирован ли пользователь.

Однако я изо всех сил пытаюсь заставить работать частные каналы. Попытка аутентификации всегда дает мне эту ошибку:

Access to XMLHttpRequest at 'https://my-app.test/broadcasting/auth' from origin 'https://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Я знаю, что эта ошибка CORS возникает у меня, когда у меня возникают проблемы с сервером, поэтому я попытался отладить запрос в Insomnia. Однако при имитации запроса в Insomnia он дает ответ 200, а также то, что можно было бы ожидать:

Имитировать запрос аутентификации в Insomnia

Я читал несколько руководств и вопросы о stackoverflow, но не могу найти ничего похожего. Возвращение к этому может быть связано с проблемами CORS, но я не думаю, что это так. Мой запрос OPTIONS возвращается в нормальном состоянии.

Для полноты я также добавляю код, который может помочь в отладке.

Мой BroadcastServiceProvider

public function boot()
{
    Broadcast::routes(['middleware' => ['auth:api']]);

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

Мои каналы .php

use Illuminate\Support\Facades\Broadcast;

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

Клиент

this.echoClient = new Echo({
  broadcaster: 'pusher',
  key: process.env.VUE_APP_WEBSOCKETS_APP_ID,
  wsHost: process.env.VUE_APP_WEBSOCKETS_URL,
  wssPort: 6001,
  // forceTLS: true,
  disableStats: true,
  authEndpoint: process.env.VUE_APP_SERVER_URL + '/broadcasting/auth',
  auth: {
    headers: {
      Authorization: "Bearer " + this.$store.state.auth.auth_token
    }
  }
})

// this one works!!
this.echoClient.channel('App.User')
  .listen('UpdatePosts', (e) => {
    console.log('event received')
    console.log(e)
  })

// private channels don't work ... :'(
this.echoClient.private('App.User.' + this.user.id)
  .listen('UpdatePosts', function(e) {
    console.log(e)
  })

person Dante    schedule 24.12.2020    source источник
comment
какой api вы используете? laravel santum?   -  person Kamlesh Paul    schedule 24.12.2020
comment
@KamleshPaul - Я использую Laravel Passport.   -  person Dante    schedule 24.12.2020


Ответы (2)


У меня та же проблема. Используя Fruitcake / laravel-cors, она была решена.

это мой вариант авторизации:

    auth : {
        headers : {
             Authorization: "Bearer " + token,
             Accept: "application/json",

        }
    },
person Mohammad Aliyari    schedule 24.12.2020
comment
Спасибо за ответ. Похоже, это не решает мою проблему. Я вижу, что Accept: application / json добавлен в мои заголовки запросов, но проблема все та же. - person Dante; 24.12.2020
comment
Кстати - ›Я также использую кекс / ларавель-корс! + Как вы узнали, что это нужно добавить? - person Dante; 24.12.2020
comment
Уважаемый, я просто делюсь своим опытом ... попробуйте установить useTLS false в broadcasting.php, помимо forceTLS:false Надеюсь, это решит вашу проблему - person Mohammad Aliyari; 24.12.2020
comment
Спасибо за вашу помощь. к сожалению, это не решает мою проблему. Действительно странно, что в Insomnia все работает нормально, но я получаю эти ошибки в браузере. - person Dante; 24.12.2020

для всех, кто борется с этой проблемой. Для меня решением было добавить префикс api к методу broadcast :: auth.

public function boot()
{
    Broadcast::routes(['prefix' => 'api', 'middleware' => ['auth:api']]);

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

Конечно, нужно правильно установить префикс api на клиенте:

  authEndpoint: process.env.VUE_APP_SERVER_URL + '/api/broadcasting/auth',

Я полагаю, разница в том, что когда вы префикс api Laravel, мы специально говорим серверу отказаться от веб-промежуточного программного обеспечения.

Я до сих пор не совсем понимаю, почему запрос от Insomnia был успешным, поскольку не было установлено заголовок x-csrf. Insomnia отправила заголовок cookie. Может, поэтому он там работал.

РЕДАКТИРОВАТЬ

Решение предоставлено @Tippin на форуме ларакастов.

Чтобы добавить к ответу, в конце концов, это была проблема CORS.

https://github.com/fruitcake/laravel-cors

Приставка к широковещательному маршруту с помощью API вообще не изменяет промежуточное программное обеспечение, поэтому оно не помещается в группу промежуточного программного обеспечения api. Я думаю, что происходит то, что у вас может быть установлен пакет cors, а в разрешенных путях у вас есть что-то вроде api / *, поэтому, просто добавив этот префикс, вы решили свою проблему. В противном случае вы можете добавить трансляцию по умолчанию в белый список (при условии, что вы используете этот пакет для CORS):

/*
 * You can enable CORS for 1 or multiple paths.
 * Example: ['api/*']
 */
'paths' => ['api/*', 'broadcasting/auth'],

https://github.com/fruitcake/laravel-cors/blob/master/config/cors.php

person Dante    schedule 24.12.2020