Node.js 和 socket.io 的 Redis 身份验证错误
Posted
技术标签:
【中文标题】Node.js 和 socket.io 的 Redis 身份验证错误【英文标题】:Redis auth error with Node.js and socket.io 【发布时间】:2012-11-06 11:28:54 【问题描述】:我可以在没有密码的情况下将我的 Node 应用程序连接到 Redis,但是当我添加密码时,我所做的一切都是正确的。
这是我现在的代码,取自an example:
var redis = require('redis')
, sio = require('socket.io')
, RedisStore = sio.RedisStore
, io = sio.listen();
var port = 6379
, hostname = 'localhost'
, password = 'password';
var redisClient = redis.createClient(port, hostname);
redisClient.auth(password, function (err) if (err) throw err; );
var redisSubscriber = redis.createClient(port, hostname);
redisSubscriber.auth(password, function (err) if (err) throw err; );
io.set('store', new RedisStore( redisPub: redisClient, redisSub: redisSubscriber, redisClient: redisClient ));
在运行应用程序时,我得到了这个堆栈跟踪:
/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/index.js:506
throw callback_err;
^
Error: Ready check failed: ERR operation not permitted
at RedisClient.on_info_cmd (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/index.js:319:35)
at Command.RedisClient.ready_check.send_anyway [as callback] (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/index.js:367:14)
at RedisClient.return_error (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/index.js:502:25)
at RedisReplyParser.RedisClient.init_parser (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/index.js:262:14)
at RedisReplyParser.EventEmitter.emit (events.js:93:17)
at RedisReplyParser.send_error (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js:266:14)
at RedisReplyParser.execute (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js:125:22)
at RedisClient.on_data (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/index.js:478:27)
at Socket.<anonymous> (/home/eric/christmas/sockets/node_modules/socket.io/node_modules/redis/index.js:79:14)
at Socket.EventEmitter.emit (events.js:93:17)
生成此行是最后一行 - 如果我注释掉设置 RedisStore 的尝试,我不会收到任何错误。
我确定密码正确(我可以在 redis-cli 中验证它,如果我将密码更改为错误,我可以验证身份验证回调不会触发)。如果我删除密码并注释掉两个身份验证行,此代码也可以工作。
博客文章和文档等上的所有工作示例都表明这应该有效,我不知道为什么我的不是。我不知道要看堆栈的哪一部分。
当我运行上面的代码时,redis-cli 监视器是这样的:
1353227107.912512 [0 127.0.0.1:56759] "auth" "password"
1353227107.912719 [0 127.0.0.1:56758] "auth" "password"
1353227107.913470 [0 127.0.0.1:56759] "info"
1353227107.913639 [0 127.0.0.1:56758] "info"
如果我关闭密码、注释掉上面的 auth 行并成功运行应用程序,redis-cli 监视器会显示以下内容:
1353227252.401667 [0 127.0.0.1:56771] "info"
1353227252.402020 [0 127.0.0.1:56770] "info"
1353227252.402131 [0 127.0.0.1:56769] "info"
1353227252.402423 [0 127.0.0.1:56768] "info"
1353227252.402611 [0 127.0.0.1:56767] "info"
1353227252.406254 [0 127.0.0.1:56770] "subscribe" "handshake"
1353227252.406287 [0 127.0.0.1:56770] "subscribe" "connect"
1353227252.406314 [0 127.0.0.1:56770] "subscribe" "open"
1353227252.406321 [0 127.0.0.1:56770] "subscribe" "join"
1353227252.406326 [0 127.0.0.1:56770] "subscribe" "leave"
1353227252.406337 [0 127.0.0.1:56770] "subscribe" "close"
1353227252.406354 [0 127.0.0.1:56770] "subscribe" "dispatch"
1353227252.406372 [0 127.0.0.1:56770] "subscribe" "disconnect"
成功的(无密码)连接发出 5 个“信息”命令,而我不成功的(有密码的)命令发出 2 个 - 然后在调用“on_info_cmd”方法时死掉。
任何人都可以理解这一点吗?感谢您提供的任何帮助。
【问题讨论】:
我解决了这个问题(答案如下),并更新了 Socket.io wiki 以提供授权 RedisStore 的示例:github.com/LearnBoost/socket.io/wiki/Configuring-Socket.IO 【参考方案1】:我通过将 redis 模块本身作为选项传递给 RedisStore 构造函数来解决这个问题。
io.set('store', new RedisStore(redis: redis, redisPub: redisClient, redisSub: redisSubscriber, redisClient: redisClient ));
这是客户端对象通过instanceof RedisClient
测试所必需的,并且在没有密码的情况下不会重新初始化。显然,当RedisStore
重新需要redis 模块时,使用createClient
方法创建的redis 客户端是某个新类或其他东西的成员。
我通过查看有人在 socket.io 的 issue #808 上遇到的相关问题发现了这一点。
【讨论】:
有不同的错误,但相同的解决方案有帮助...可能发生了错误,因为 Redis 也用于 Express 会话,也许不同的模块用于存储和客户端?【参考方案2】:尝试只调用一次redisClient.auth(password, function (err) if (err) throw err; );
,redis存储每次调用的auth信息,调用两次可能会报错。
【讨论】:
实际上每个客户端只调用一次——第一次在redisClient上,第二次在redisSubscriber上,一个单独的实例。 是的,我明白了,但是客户端“隐藏”了密码,因此您不需要为多个实例调用它。请看Node_redis和Auth Example 这是不正确的 - 它按实例存储它,而不是整个班级。我见过的每个创建 pub、sub 和 store 客户端的 redis 身份验证示例都使用这种模式。示例:github.com/LearnBoost/socket.io/pull/551 @yeah,存储用于重新连接同一客户端实例 AFAIK,它不在不同客户端之间共享。以上是关于Node.js 和 socket.io 的 Redis 身份验证错误的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Asterisk ARI 与 socket.io 和 Node.js 一起使用
Phaser.js 中的 Node.js 和 Socket.io 未连接 socket.io/?EIO=3&transport=polling