Redis、Node.js 和 Socket.io:跨服务器认证和 node.js 理解 [英] Redis, Node.js, and Socket.io : Cross server authentication and node.js understanding

查看:77
本文介绍了Redis、Node.js 和 Socket.io:跨服务器认证和 node.js 理解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在 Rails 和 Backbone.js 上运行的单页应用程序.我正在通过 Redis 使用 Node.js 向客户端推送和同步数据.我正在尝试了解、保护和优化套接字通信.

I got a single-page application running on Rails and Backbone.js. I'm using Node.js through Redis to push and synchronize data to clients. I am trying to understand, secure and optimize sockets communications.

使用 console.log 编写时,我看到一些日志行 (console.log('Redis connection on ..')) 出现重复(见下文).

When writing with console.log I see some log lines (console.log('Redis connection on ..')) are getting duplicate (see bellow).

谁能解释一下为什么?通过我的代码实现,是否有一些我不理解的特定 Node.js 行为?

Does anyone can explain me why ? Is there some specific Node.js behaviours I'm not understanding, through my code implementation ?

这是我的 Node.js 代码:

Here's my Node.js code:

var io = require('socket.io').listen(3003);
var redis = require('redis');
var cookie = require("cookie");
var redis_subs = redis.createClient(6379, "localhost");
var redis_auth = redis.createClient(6379, "localhost");
var authenticated = false;

var authentication_status = function (status) {
  if (status === true) {
    console.log('Authentication status is true.');
  }
  else {
    console.log('Authentication status is false.');
  }
  authenticated = status;
};

redis_subs.subscribe('application_channel');

io.configure(function () {
  io.set('authorization', function (data, callback) {
    console.log('Cross authentication...');
    if (data.headers.cookie) {
      data.cookie = cookie.parse(data.headers.cookie);
      data.sessionID = data.cookie['_validation_token_key'];
      redis_auth.hget(["sessionStore", data.sessionID], function (err, session) {
        if (err || !session) {
          console.log('Socket.io authorization say false');
          return callback(authentication_status(false), false);
        }
        else {
          data.session = JSON.parse(session);
          console.log('Socket.io authorization say true');
          return callback(authentication_status(true), true);
        }
      });
    }
    else {
      console.log('Socket.io authorization say false');
      return callback(authentication_status(false), false);
    }
  });
});

io.on('connection', function(socket){
    if (socket.handshake.session) {
      var user_socket_channel = socket.handshake.session['user_socket_channel']
      redis_subs.on('message', function(redis_channel, rawdata) {
        console.log('Redis connection on '+redis_channel);
        console.log('Handshaked Session, authenticated user. All channels allowed.');
        var data = JSON.parse(rawdata);
        if (data.channel) { var socket_channel = data.channel; }
        else { var socket_channel = user_socket_channel; }
        var rails_data = data.data;
        console.log('Socket.io emiting on ['+socket_channel+']')
        socket.emit(socket_channel, rails_data);
      });
    }
    else {
      redis_subs.on('message', function(redis_channel, rawdata) {
        console.log('Redis connection on '+redis_channel);
        console.log('No handshaked Session, unauthenticated user. Public channels allowed.');
        var data = JSON.parse(rawdata);
        var rails_data = data.data;
        console.log('Socket.io emiting on [public]')
        socket.emit('public', rails_data);
      });
    }
});

这是我测试它的方式,以及日志重复的特定用例:

Here is the way I am testing it, and the specific use case where log is getting duplicate :

在登录时加载页面,使用网络浏览器1(例如:Firefox);输出:

Loading the page while being logged-in, with web browser1 (e.g: Firefox); output:

   info  - socket.io started
Cross authentication...
Socket.io authorization say true
Authentication status is true.
   debug - authorized
   info  - handshake authorized bJxm_IcWl2mKZT4Ed-kV
   debug - setting request GET /socket.io/1/websocket/bJxm_IcWl2mKZT4Ed-kV
   debug - set heartbeat interval for client bJxm_IcWl2mKZT4Ed-kV
   debug - client authorized for 
   debug - websocket writing 1::

加载使用 browser2 注销的同一页面(例如:Chrome)

Loading the same page being logged-out with browser2 (e.g: Chrome)

Cross authentication...
Socket.io authorization say false
Authentication status is false.
   debug - authorized
   info  - handshake unauthorized

通过 page/browser1 (Firefox) -> Rails -> Redis 发送一些数据,输出:

Sending some data through page/browser1 (Firefox) -> Rails -> Redis, output:

Redis connection on application_channel
Handshaked Session, authenticated user. All channels allowed.
Socket.io emiting on [hLTYXuvP+13aQlIT9CZiYc1i9eg=]
   debug - websocket writing 5:::{"name":"hLTYXuvP+13aQlIT9CZiYc1i9eg=","args":[null]}

在浏览器2(Chrome,已注销)上重新加载页面,仍然输出

Reloading the page on browser2(Chrome, logged-out), still output

Cross authentication...
Socket.io authorization say false
Authentication status is false.
   debug - authorized
   info  - handshake unauthorized

在 browser1/Firefox 上重新加载页面,并通过页面和 Rails 向 Redis 推送更多数据,输出:

Reloading the page on browser1/Firefox and pushing some more data to Redis through the page and Rails, output:

Redis connection on application_channel
Handshaked Session, authenticated user. All channels allowed.
Socket.io emiting on [hLTYXuvP+13aQlIT9CZiYc1i9eg=]
Redis connection on application_channel
Handshaked Session, authenticated user. All channels allowed.
Socket.io emiting on [hLTYXuvP+13aQlIT9CZiYc1i9eg=]
   debug - websocket writing 5:::{"name":"hLTYXuvP+13aQlIT9CZiYc1i9eg=","args":[null]}

如您所见,事件被复制,Redis 侦听器现在捕获两个连接;每次我重新加载 page1/Firefox 时,它都会再复制一次(3,4,5...).

As you can see, the event got duplicated, and the Redis listener now catch two connections; Every time I'll reload page1/Firefox, it will duplicate it one more time (3,4,5...).

我不明白这种行为.我错过了什么?顺便说一句,正如你所看到的,我不太了解 Socket.io configureset authorizationcallback 的目标,返回 true 或 false,因为 Node 正在访问 io.on('connection') 和 Redis 侦听器.

I don't understand this behaviours. What am I missing? By the way, as you can see, I don't really understand either the goal of Socket.io configure, set authorization and callback, returning true or false, as Node is reaching to io.on('connection') and Redis listeners anyway.

推荐答案

好的,我知道答案了.我很难弄清楚,已经找了几个小时......

Ok, I've got my answer. I had a hard time figuring it out, been looking for hours ...

这是使我能够使其工作的相关主题(回答和评论):

Here's the related topic that allowed me to make it work (answer AND comments):

如何在消息"侦听器上删除 Redis

这是我的代码:

io.on('connection', function(client){
    console.log('Client id #'+client.id);

    if (client.handshake.session) {
      var user_socket_channel = client.handshake.session['user_socket_channel'];
    }

    var redis_listener = function(redis_channel, rawdata) {
      console.log('Redis connection on '+redis_channel);
      var data = JSON.parse(rawdata);
      if (data.channel) { var socket_channel = data.channel; }
      else { 
        if (user_socket_channel) { var socket_channel = user_socket_channel; }
        else { var socket_channel = 'public' }
      }
      var rails_data = data.data;
      console.log('Socket.io emiting on ['+socket_channel+']');
      client.emit(socket_channel, rails_data);
    };

    redis_subs.on('message', redis_listener);

    client.on('disconnect', function(){
      console.log('Client disconnect, removing redis listener..');
      redis_subs.removeListener('message', redis_listener);
    });
});

根据上下文,您需要在 io.client.disconnect 事件上调用 redis.removeListener.

Depending on the context, you need to call redis.removeListener on io.client.disconnect event.

这是一个可能的替代方案:

Here's a probable alternative :

https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO

顺便说一下,这个相关问题似乎是一个有准确答案的类似问题,但实际上并非如此(不起作用).此外,请查看突出显示的评论:

By the way this related question seems a similar one with an accurate answer, but isn't actually (didn't work). Further more, look at the highlighted comment:

如何在socket中重用redis连接.io?

这篇关于Redis、Node.js 和 Socket.io:跨服务器认证和 node.js 理解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆