Канал websocket для "текущего пользователя"
Используя websocket-rails, я могу использовать следующий код в моем контроллере, чтобы обмануть событие публикации websocket:
WebsocketRails[:channel_name].trigger('event_name', { foo: "bar" }.to_json)
Моя цель - создать канал pub-sub только для текущего пользователя. Возьмем, к примеру, событие "Новое сообщение в чате отправлено". Я хочу выдвинуть это событие только на канал получателя.
В настоящее время я создаю уникальное имя канала для каждого пользователя на основе его идентификатора. Я поместил следующий код в мой контроллер (определив метод current_user в другом месте:
WebsocketRails[:"user#{current_user.id}"].trigger("event_name", { foo: "bar" }.to_json)
И затем в моем Javascript я подписываю текущего пользователя на его собственный канал со следующим:
<% if @current_user %>
var dispatcher = new WebSocketRails('localhost:3000/websocket');
channel = dispatcher.subscribe('user<%= @current_user.id %>');
channel.bind('event_name', function(data) {
console.log(data)
});
<% end %>
Суть его заключается в использовании интерполяции строк для создания нового канала для каждого пользователя, т.е.user12
а также user123
каналы.
Проблема в том, что это не совсем безопасно. Любой пользователь может получить доступ к чьему-либо частному каналу, просто вставив в него некоторый Javascript. Например, если пользователь № 1 хочет получить доступ к новостной ленте пользователя № 2, он может просто набрать dispatcher.subscribe('user2')
,
Как бы вы решили эту проблему? Есть ли другая библиотека pub-sub, в которую встроена эта функция?
Просматривая вики-статью WebsocketRails по этой теме, я попытался добавить следующий код в config / initializers / websockets.rb
WebsocketRails::EventMap.describe do
namespace :websocket_rails do
subscribe :subscribe_private, to: ConnectionsController, with_method: :authorize_channels
end
end
И следующее к app / controllers / connections_controller.rb
class ConnectionsController < WebsocketRails::BaseController
def authorize_channels
channel_name = WebsocketRails[message[:channel]]
current_user = User.find_by(id: session["current_user_id"])
if current_user && "user#{current_user.id}".eql?(channel_name)
accept_channel current_user
else
deny_channel({ message: "auth failed" })
end
end
end
А потом в другом месте, я звоню WebsocketRails[:"user#{@current_user.id}"].make_private
Это, похоже, не имеет никакого эффекта.