Проблема с аутентификацией частных каналов в laravel с java-клиентом

Я хочу отправлять широковещательные сообщения с сервера (используя laravel) клиентам (используя java).

Что я использую

  1. толкатель в качестве драйвера boradcast.
  2. паспорт laravel для аутентификации API.

Что я сделал на стороне сервера

  1. Я настроил свои учетные данные Pusher в файле .env.
  2. Раскомментированная App\Providers\BroadcastServiceProvider::class строка в config/app.php файле.
  3. В файле config/auth.php я добавил следующее:
'guards' => [
     'web' => [
         'driver' => 'session',
         'provider' => 'users',
     ],

     'devices' => [
         'driver' => 'session',
         'provider' => 'devices',
     ],

     'api' => [
         'driver' => 'passport',
         'provider' => 'devices',
     ],
 ],

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\User::class,
    ],

     // using devices table to authenticate over api guard
    'devices' => [
        'driver' => 'eloquent',
        'model' => App\Device::class,
    ],
],
  1. В классе App\Providers\BroadcastServiceProvider я добавил следующее в функцию boot():
Broadcast::routes(['prefix' => 'api', 'middleware' => 'auth:api']);
  1. В routes/channels.php я добавил следующее:
Broadcast::channel('device.{device_id}', function ($device, $device_id) {
    return $device->id === $device_id;
});
  1. Создал событие AdvertisementAdded, запустив php artisan make:event AdvertisementAdded, добавил implements ShouldBroadcast, а затем добавил следующее в его метод broadcastOn():
return new PrivateChannel('device.'.$this->device_id);

Что я сделал на стороне клиента

Поскольку я сейчас только тестирую, я получил свои access_token и device_id, отправив запрос на вход от почтальона.

Проблема с аутентификацией частных каналов в laravel с java-клиентом

Я скопировал этот accessToken в свой java-клиент и сохранил его в переменной accessToken как String, вот код:

String accessToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImY3ZTVlMTAzZWE3MzJjMTI5NzY1YTliMmMzOTM0N2ZhOGE4OTU5MjRjNDA5ZjgyOTA4ZDg5NTFjZTBkOGZlNTA2M2M1YTI1MDBlOTdhZDdiIn0.eyJhdWQiOiIxIiwianRpIjoiZjdlNWUxMDNlYTczMmMxMjk3NjVhOWIyYzM5MzQ3ZmE4YTg5NTkyNGM0MDlmODI5MDhkODk1MWNlMGQ4ZmU1MDYzYzVhMjUwMGU5N2FkN2IiLCJpYXQiOjE1NTkwOTYyNDgsIm5iZiI6MTU1OTA5NjI0OCwiZXhwIjoxNTkwNzE4NjQ3LCJzdWIiOiI3Iiwic2NvcGVzIjpbXX0.FKeE9Z-wv2yUNQPl-qsbu9baYGTdbQ6DuzaI1R8azR6l1CIP9uRI4hCaoWvgx0GXWWLPRNhfQl-YD3KP2YOraW16-h4ie_95B9VQrpFxXnlqKojsfh1xSrSNSl5HncslMWQPVjoesBpM5y_cpG19PGgu-SWo0W6s9Fiz_Nm70oyyZB9mSqU8PVQvAOSNr6TMR0aC3iMLFfkyZkTSwj8EoRyD2LGW6v4PFriqx8JLbZASCOiUYBlYnunWrTFDOAenZcoa5Sw7u7kbSvYehjDKRwKjQM6zmPfi0A3Mp0CHjHE599OXb-NG2IMH-wmlT0vEZjP2U97hxmsNW1RtHNXWaRKFL9T-WVmZbJf3fH5hXqTv495L3MQfq_m5YFHyc5NuIqK4K4xMJB956a33ICnH8DmvPmJgderNAhqEX1JHUAsR63K7xbZxRBDS8OlQYcEf-_v75X0kT1s067enSvI8Vs212AVnI6k0FmgQNM8DfJUq6YduD0m2F2ZWpKPrwdd6PdW5ZlZTEv-D8dYIEQ_CwOWohNoENATmTqxDpPBxK5c723MEt8S7Sa9MEGAo56HW3-9pbazbEdY1GqPWKVkov7K_6eBFcWsV67AgJpoKFt6RiBfRvokgiH96WG89qBB_Ucpm8uBahX93FaOXhVLW0VjJH2LQKrGw0bb5LS8Ql5o";
String deviceId = "7";

Map<String, String> authHeaders = new HashMap();

authHeaders.put("Authorization", accessToken);

HttpAuthorizer authorizer = new HttpAuthorizer("http://localhost:8000/api/broadcasting/auth");
authorizer.setHeaders(authHeaders);
PusherOptions options = new PusherOptions();
options.setAuthorizer(authorizer).setCluster(PUSHER_CLUSTER);
Pusher pusher = new Pusher(PUSHER_APP_KEY, options);

pusher.subscribePrivate("private-device." + deviceId, new PrivateChannelEventListener() {
    @Override
    public void onEvent(String channelName, String eventName, final String data) {
        System.out.println(String.format("Received event on channel [%s]", channelName));
    }

    @Override
    public void onSubscriptionSucceeded(String string) {
        System.out.println(String.format("Subscribed to channel [%s]", string));
    }

    @Override
    public void onAuthenticationFailure(String string, Exception excptn) {
        System.out.println(string);
    }
});

pusher.connect(new ConnectionEventListener() {
    @Override
    public void onConnectionStateChange(ConnectionStateChange change) {
        System.out.println("State changed to " + change.getCurrentState() +
                           " from " + change.getPreviousState());
    }

    @Override
    public void onError(String message, String code, Exception e) {
        System.out.println("There was a problem connecting!");
    }
});

// Keeping main thread alive
while (true) {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

При запуске приведенного выше кода он выводит на консоль следующее:

State changed to CONNECTING from DISCONNECTED
State changed to CONNECTED from CONNECTING
java.io.IOException: Server returned HTTP response code: 403 for URL: http://localhost:8000/api/broadcasting/auth

Я уверен, что промежуточное ПО auth:api работает так, как я ожидаю, по другим запросам.

Вот фрагмент из моего routes/api.php:

Route::middleware('auth:api')->group(function () {
    Route::prefix('advertisements')->group(function () {
        Route::get('/request', 'AdvertisementsController@getDeviceAdvertisements')
            ->name('advertisements.getDeviceAdvertisements');
    });
});

И вот тест этого маршрута от почтальона (с тем же токеном доступа, что и выше):

Проблема с аутентификацией частных каналов в laravel с java-клиентом

А вот тест маршрута api/broadcasting/auth от почтальона (с тем же токеном доступа, что и выше):

Проблема с аутентификацией частных каналов в laravel с java-клиентом

В чем проблема? Почему все маршруты API в auth:api промежуточном программном обеспечении работают правильно, но не api/broadcasting/auth маршрут ??

Примечание

Пробовал работать с публичными каналами без проблем.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
574
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После целого дня поисков, наконец, это решено.

Ошибка возникает при авторизации канала, а не при аутентификации запроса с помощью auth:api промежуточного ПО.

Моя функция авторизации частного канала в routes/channels.php всегда возвращает false, что означает, что она будет отклонять все запросы на подписку на канал private-device.{device_id}:

Broadcast::channel('device.{device_id}', function ($device, $device_id) {
    // this always return false, because of inequality of types
    return $device->id === $device_id;
});

Функция авторизации выше всегда возвращает false из-за неравенства типов между $device->id (типа int) и $device_id (типа string).

Итак, чтобы решить проблему, я привел их обоих к int, а затем проверил на равенство.

Вот код, который я использовал для решения проблемы:

Broadcast::channel('device.{device_id}', function ($device, $device_id) {
    return (int) $device->id === (int) $device_id;
});

Другие вопросы по теме