Чат в реальном времени в PHP + Redis + Pub / Sub + WebSockets (+ NodeJS)

Я хочу разработать чат с каналами в реальном времени, и это мои потребности:

  • PHP-бэкэнд для управления сайтом
  • Redis как первичное хранилище сессий и данных
  • Pub / Sub для отправки сообщений только заинтересованным пользователям канала
  • одно соединение WebSocket, с помощью которого сообщения будут отправляться и приниматься.
  • (необязательно) NodeJS для использования отличных пакетов npm, таких как timesync или socket.io

Я вижу две разные архитектуры для достижения этой цели:

  • с Socket.io

    socket.io

  • с Crossbar.io

    crossbar.io

Это мои вопросы:

  1. Какую архитектуру выбрать и почему?
  2. Ключ в том, что идентификатор пользователя не может быть получен от клиента, потому что он может быть искажен. Итак, в первой архитектуре я думаю, что к каждому сообщению сокета я должен прикрепить значение PHPSESSID из файла cookie, а на стороне сервера получить сеанс PHP из Redis. Я прав или есть способ получить идентификатор пользователя лучше?
  3. Интересно, можно ли получить идентификатор пользователя во второй архитектуре по-другому?

Изменить:

Я выбрал Crossbar.io, потому что он очень мощный и позволяет общаться с множеством различных языковых приложений в реальном времени. Изучив примеры, я пришел к следующему:

  • При каждом входе в систему пользователь генерирует секретный ключ в базе данных.

  • Клиент PHP (Thruway) подключается к серверу Crossbar и регистрирует собственный аутентификатор WAMP-CRA

  • Браузер пользователя подключается к серверу Crossbar и получает запрос. Секрет и auth_id (идентификатор пользователя) загружаются из БД при загрузке страницы, поэтому он может выполнить запрос и отправить ответ.

  • Поиск аутентификатора PHP в БД для пользователя с предоставленным секретом и идентификатором, равным auth_id. Если есть, то он успешно аутентифицирует сеанс. Теперь мы можем быть уверены, что auth_id - это настоящий идентификатор пользователя.

Это мой вопрос:

  1. Как я могу получить auth_id при подписке?

  2. Я также добавил аутентификацию cookie, и браузер запоминается после аутентификации. Но когда я смотрю в Chrome DevTools, в локальном хранилище нет файлов cookie или значений. Даже после очистки кеша мой браузер все еще запоминается Crossbar. Интересно, как это возможно?

Edit2:

Может быть, меня неправильно поняли, но главный вопрос заключался в выборе подходящей архитектуры и получении доверенного идентификатора пользователя. Не было никакого внимания, поэтому я назначил награду, и после этого меня проголосовали против. Я много читал о приложениях реального времени и, наконец, решил использовать Crossbar.io, поэтому отредактировал вопрос, чтобы он был связан с ним. Потом люди начали голосовать, предлагая другие архитектуры, но не отвечая на мои вопросы. В конце концов, я сам это сделал и представил свой ответ.


person andrzej1_1    schedule 08.03.2017    source источник
comment
Что вы имеете в виду под PHP-сервером для управления сайтом? Я думаю, что ваш HTML-интерфейс чата не обязательно должен обслуживаться сервером PHP. Затем становится легче, вы можете использовать либо серверную часть nodejs, либо RatchetPHP для обеспечения сервера чата, а также интерфейсную часть HTML + js + autobahnjs.   -  person Alcalyn    schedule 08.03.2017
comment
Чат @Alcalyn - это лишь небольшая часть сайта, и я хочу управлять пользователями, сообщениями и другими вещами из моей PHP-среды.   -  person andrzej1_1    schedule 08.03.2017
comment
Либо существует слишком много возможных ответов, либо хорошие ответы будут слишком длинными для этого формата. Добавьте подробности, чтобы сузить набор ответов или выделить проблему, на которую можно ответить в нескольких абзацах. Я бы посоветовал вам найти форум разработчиков (возможно, Quora?), Чтобы обсудить общие вопросы. Затем, если / если у вас возникнут определенные проблемы с кодированием, вернитесь к Stack Overflow, и мы будем рады помочь.   -  person Jay Blanchard    schedule 14.03.2017
comment
@JayBlanchard Я ожидал много общих ответов, но теперь я полностью изменил свой вопрос, и на него должно быть легче ответить.   -  person andrzej1_1    schedule 16.03.2017
comment
Вопросы, которые вы задаете при редактировании, также довольно широки.   -  person Jay Blanchard    schedule 16.03.2017
comment
@JayBlanchard Если кто-то не ответит в течение времени награды, я просто удалю вопрос   -  person andrzej1_1    schedule 16.03.2017


Ответы (3)


О получении идентификатора пользователя:

Каждый пример чата в реальном времени, который я видел, получал идентификатор от клиента. Это небезопасно, потому что клиент легко может им манипулировать, поэтому мне нужно было найти другой метод. Прочитав спецификации WAMP, я наконец понял что я должен аутентифицировать пользователя не только в приложении, но и в Crossbar.io. Я выбрал динамический метод WAMP-CRA и реализовал его следующим образом:

  • Приложение PHP подключается к серверу Crossbar и регистрирует пользовательский аутентификатор (аналогично пример)
  • После входа пользователя в приложение для него создается секретный ключ, который сохраняется в базе данных. После выхода ключ уничтожается.
  • Рабочий процесс:

    1. Каждая загруженная страница содержит идентификатор пользователя и секретный ключ, загруженные из базы данных:

      <script>
          auth_id = '<?php echo $user->id ?>';
          secret_key = '<?php echo $user->secret_key ?>';
      </script>
      
    2. Пользовательский браузер подключается к серверу Crossbar.io и получает ответ с запросом от пользовательского аутентификатора.
    3. Он вычисляет подпись с помощью key и отправляет вместе с auth_id на сервер Crossbar.io.
    4. Аутентификатор получает из БД секрет для предоставленного auth_id и вычисляет подпись. Затем подписи сравниваются, и если они равны, то аутентификация успешна.
    5. Теперь auth_id содержит идентификатор пользователя, и мы можем доверять его значению. Теперь вы можете обратиться к разделу «Как я могу получить auth_id при подписке?».

Ответы:

Как я могу получить auth_id при подписке?

По умолчанию издатели и подписчики ничего не знают друг о друге, но документация показывает, что существует возможность изменить его, настроив раскрытие личности вызывающего абонента. Затем вы можете получить auth_id из деталей обратного вызова:

  • PHP:

    $onEvent = function ($args, $argsKw, $details, $publicationId) use ($session) {
        $auth_id = $details->publisher_authid;
        ...
    }
    $session->register('com.example.event', $onEvent);
    
  • JS:

    function on_event(args, kwargs, details) {
        auth_id = details['publisher_authid'];
        ...
    }
    session.subscribe('com.example.event', on_event);
    

Я также добавил аутентификацию cookie, и браузер запоминается после аутентификации. Но когда я смотрю в Chrome DevTools, в локальном хранилище нет файлов cookie или значений. Даже после очистки кеша мой браузер все еще запоминается Crossbar. Интересно, как это возможно?

Прежде всего, очистка кеша и жесткая перезагрузка не удаляют файлы cookie. Когда я задавал этот вопрос, был представлен какой-либо файл cookie, но сегодня я вижу cbtid: cookiesЧерез два дня было обновление Chrome назад, так что, возможно, это было вызвано ошибкой в ​​предыдущей версии.

person andrzej1_1    schedule 19.03.2017

Я глубоко освещаю Streamer, который используется НАСА для пересылки грузовиков данных в секунду. Самый надежный сервер для обмена сообщениями в реальном времени. Мощные веб-приложения, приложения для мобильных устройств, планшетов, компьютеров и Интернета вещей.

Оптимизированная потоковая передача данных для Интернета и мобильных устройств. Lightstreamer поддерживает несколько форм обмена сообщениями в реальном времени. Он достаточно гибкий, чтобы его можно было использовать в любом сценарии, включая критически важные приложения. ► Отправка данных в реальном времени и веб-сокеты

Что касается вашего первого вопроса, чтобы получить auth_id при подписке, просто отслеживайте подписки на подключение, а затем сохраняйте уровень после успешного подключения. Также не рекомендуется использовать файлы cookie, используйте jwt. Веб-токены JSON - это открытый отраслевой стандартный метод RFC 7519 для безопасного представления претензий между двумя сторонами. Аутентификация является одной из основных частей каждого приложения. Безопасность - это всегда что-то, что меняется и развивается. JWT помогает вам решить эту проблему, поскольку он не имеет состояния.

person Remario    schedule 18.03.2017
comment
Если бы вы придумали LighStreamer с JWT до того, как я выбрал архитектуру, я бы принял ваш ответ. Но вы делаете это после того, как мой вопрос был связан с Crossbar.io. - person andrzej1_1; 19.03.2017

PHP Ratchet - одна из лучших реализаций, которые я использовал для связи в реальном времени через WebSockets. Он основан на сокетах ZMQ, которые используются в нескольких игровых онлайн-приложениях и приложениях для чата.

Следующие примеры помогут вам быстро начать работу и ответят на ваши вопросы о auth_id и подписках:

http://socketo.me/docs/hello-world

http://socketo.me/docs/push

Обзор архитектуры:

http://socketo.me/docs/push#networkarchitecture

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

person Arithran    schedule 17.03.2017
comment
Приведенные вами примеры основаны на отправке формы / ajax, поэтому это не удовлетворяет мою потребность: одно соединение WebSocket, с помощью которого сообщения будут отправляться и приниматься. - person andrzej1_1; 17.03.2017