Авторизация для паспорта laravel через socket.io для каналов вещания

Я использую laravel 5.3 + паспорт для авторизации, Laravel мой бэкэнд API, который restful,

интерфейс написан на angular.js которые общаются с API с запросами отдыха.

Для уведомлений в реальном времени я использовал laravel трансляция событий + redis, а также socket.io для сокет-сервера и сокет-клиента в angular.js.

Я хочу разрешить эти события, и я сделал это, насколько мог:

BroadcastServiceProvider:

public function boot()
{
   Broadcast::routes(['middleware' => ['auth:api']]);
   Broadcast::channel('App.User.*', function ($user, $userId) 
   {
     return (int) $user->id === (int) $userId;
   });

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

Это мой код socket.js, который запускает мой сервер сокетов:

var app   = require('express')();
var http  = require('http').Server(app);
var io    = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();

redis.psubscribe('*', function(err, count) {});

redis.on('pmessage', function(subscribed, channel, message) {
    console.log(channel);
    message = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.data);
});

http.listen(3000, function () {
    console.log('Listening on Port 3000');
});

redis.on("error", function (err) {
    console.log(err);
});

Проблема в том, что я не знаю, как аутентифицировать эти широковещательные события на сервере сокетов, а также как авторизовать пользователя в angular.js (SPA) слушать эти события.

Буду признателен за любую помощь.

1 ответ

Решение

Я бы определенно взглянул на socketio-auth.

Этот модуль предоставляет хуки для реализации аутентификации в socket.io без использования строк запросов для отправки учетных данных, что не является хорошей практикой безопасности.

Другой подход, который я недавно использовал, - простая аутентификация на основе токенов с использованием токенов JWT ( njwt).

Я не хотел воссоздавать код аутентификации, который проверяет учетные данные пользователя в Node.js. (который в моем случае не может даже подключиться к базе данных в любом случае). Скорее, я бы позволил приложению PHP, использующему сокет, использовать уже установленную систему аутентификации. Передача подписанного токена с запросами на подключение к сокету.

Ваш код node.JS может выглядеть примерно так...

primus.on('connection', function (spark) {

    logger.debug('primus event connection.  spark id: ' + spark.id);

    spark.on('data', function(data) {

        var action = data.action;

        njwt.verify(data.token, JWT_SECRET, function(err, verifiedJwt) {
            if (err) {
                logger.warn('Bad JWT Token! ' + spark.id + ' Error: ' + err);
                spark.user = {id:null, is_authed: false, is_admin: false, application_ini: null};
                spark.end('Bad Token Request');
                return; //->
            }

            spark.user = {  'id': verifiedJwt.body['user_id'],
                            'is_authed': verifiedJwt.body['is_authed'],
                            'application_ini': verifiedJwt.body['application_ini'],
                            'is_admin': verifiedJwt.body['is_admin']};

            sockoasRooms.connect(spark.id, spark.user.application_ini, spark.user.id); 


            switch (action) {
            ...

А затем на стороне PHP вам понадобится код для генерации токенов JWT, но использовать его очень просто. Что-то вроде:

<?php
$tokenPayload = [   'user_id'           => ($this->currentUser) ? $this->currentUser->getId() : 0,
                    'is_authed'         => ($this->currentUser) ? true : false,
                    'application_ini'   => (string) APPLICATION_INI,
                    'is_admin'          => (bool) ($this->currentUser) ? $this->currentUser->isAdministrator() : false,
                    'now'               => time()
];
$jwtToken = \OAS_JWT::encode($tokenPayload, SOCK_OAS_JWT_KEY);

?>

$(document).ready(function() {

    primus = Primus.connect('ws://<?=SOCK_OAS_IP?>:<?=SOCK_OAS_PORT?>/_admin');

    primus.on('open', function () {
        showConnected();
        // Send request to subscribe
        primus.write({action: 'dashboard-dump', token: '<?=$jwtToken?>'});
        consoleWrite('Connected to dashboard.');
    });

Вы можете оценить компонент времени, чтобы избежать повторных атак. В любом случае, похоже, что этот подход может удовлетворить ваши потребности.

Не по теме, но я бы также посоветовал взглянуть на примус. Он действует как "универсальная оболочка для сред реального времени". Это позволяет вам абстрагировать вещи таким образом, чтобы вы могли без проблем менять библиотеки сокетов. Может быть немного ниже уровня (engine.IO), чем то, что вы используете, хотя.

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