为socket.io/nodejs验证用户

Joh*_*ohn 40 php session node.js socket.io

我有一个php登录,用户输入用户名/密码,它会根据登录信息检查mysql数据库.如果经过身份验证,则会通过php创建会话,用户现在可以使用php会话访问系统.我的问题是,一旦他们通过php/session进行身份验证,那么授权用户查看他们是否具有使用socket.io访问nodejs服务器的正确登录权限的过程是什么?我不希望这个人有权访问nodejs/socket.io函数/服务器,除非他们通过php登录验证.

Alf*_*red 62

更新

要求:

  1. 首先让redis运行.
  2. 接下来启动socket.io.
  3. 最后上传/托管PHP(在归档中有依赖关系).

Socket.io

var express = require('express'),
        app         = express.createServer(),
        sio         = require('socket.io'),
        redis   = require("redis"),
    client  = redis.createClient(),
        io          = null;

/**
 *  Used to parse cookie
 */
function parse_cookies(_cookies) {
    var cookies = {};

    _cookies && _cookies.split(';').forEach(function( cookie ) {
        var parts = cookie.split('=');
        cookies[ parts[ 0 ].trim() ] = ( parts[ 1 ] || '' ).trim();
    });

    return cookies;
}

app.listen(3000, "localhost");
io = sio.listen(app);

io.of('/private').authorization(function (handshakeData, callback) {
        var cookies = parse_cookies(handshakeData.headers.cookie);

        client.get(cookies.PHPSESSID, function (err, reply) {
                handshakeData.identity = reply;
                callback(false, reply !== null);
        });
}).on('connection' , function (socket) {
        socket.emit('identity', socket.handshake.identity);
});
Run Code Online (Sandbox Code Playgroud)

PHP

php with openid authentication => http://dl.dropbox.com/u/314941/6503745/php.tar.gz

登录后,您必须重新加载client.php进行身份验证


ps:我真的不喜欢创建甚至另一个可能不安全的密码的概念.我建议你看看openID(例如通过谷歌),Facebook Connect(仅举几个选项).

我的问题是,一旦他们通过php/session进行身份验证,那么验证用户是否拥有使用socket.io访问nodejs服务器的正确登录权限的过程是什么?我不希望这个人有权访问nodejs/socket.io函数/服务器,除非他们通过php登录验证.

将唯一的session_id添加到允许的id的列表/集合中,以便socket.io可以授权(搜索授权功能)该连接.我会让PHP使用redis与node.js通信,因为这将是闪电般快/真棒:).现在我正在伪造PHP通信redis-cli

安装Redis

下载redis =>现在可以从以下网址下载稳定版本:http://redis.googlecode.com/files/redis-2.2.11.tar.gz

alfred@alfred-laptop:~$ mkdir ~/6502031
alfred@alfred-laptop:~/6502031$ cd ~/6502031/
alfred@alfred-laptop:~/6502031$ tar xfz redis-2.2.11.tar.gz 
alfred@alfred-laptop:~/6502031$ cd redis-2.2.11/src
alfred@alfred-laptop:~/6502031/redis-2.2.11/src$ make # wait couple of seconds
Run Code Online (Sandbox Code Playgroud)

启动Redis服务器

alfred@alfred-laptop:~/6502031/redis-2.2.11/src$ ./redis-server 
Run Code Online (Sandbox Code Playgroud)

Socket.io

npm依赖项

如果npm尚未安装,请先访问http://npmjs.org

npm install express
npm install socket.io
npm install redis
Run Code Online (Sandbox Code Playgroud)

列出我已经安装的依赖项,如果根据不兼容性,你也应该安装它们 npm ls

alfred@alfred-laptop:~/node/socketio-demo$ npm ls
/home/alfred/node/socketio-demo
??? express@2.3.12 
? ??? connect@1.5.1 
? ??? mime@1.2.2 
? ??? qs@0.1.0 
??? hiredis@0.1.12 
??? redis@0.6.0 
??? socket.io@0.7.2 
  ??? policyfile@0.0.3 
  ??? socket.io-client@0.7.2 
Run Code Online (Sandbox Code Playgroud)

server.js

var express = require('express'),
        app         = express.createServer(),
        sio         = require('socket.io'),
        redis   = require("redis"),
    client  = redis.createClient(),
        io          = null;

/**
 *  Used to parse cookie
 */
function parse_cookies(_cookies) {
    var cookies = {};

    _cookies && _cookies.split(';').forEach(function( cookie ) {
        var parts = cookie.split('=');
        cookies[ parts[ 0 ].trim() ] = ( parts[ 1 ] || '' ).trim();
    });

    return cookies;
}

app.listen(3000, "localhost");
io = sio.listen(app);

io.configure(function () {
  function auth (data, fn) {
    var cookies = parse_cookies(data.headers.cookie);
    console.log('PHPSESSID: ' + cookies.PHPSESSID);

        client.sismember('sid', cookies.PHPSESSID, function (err , reply) {
            fn(null, reply);    
        });
  };

  io.set('authorization', auth);
});

io.sockets.on('connection', function (socket) {
  socket.emit('access', 'granted');
});
Run Code Online (Sandbox Code Playgroud)

要运行服务器,请运行 node server.js

client.php

<?php

session_start();

echo "<h1>SID: " . session_id() . "</h1>";
?>
<html>
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script src="http://localhost:3000/socket.io/socket.io.js"></script>
</head>
<body>
    <p id="text">access denied</p>
    <script>
        var socket = io.connect('http://localhost:3000/');
        socket.on('access', function (data) {
            $("#text").html(data);
        });
    </script>
</body>
Run Code Online (Sandbox Code Playgroud)

测试认证

当您从Web浏览器加载网页(PHP文件)时,将access denied显示该消息,但当您将session_id浏览器中显示的内容添加到redis服务器时,access granted将显示该消息.当然,通常你不会做任何复制粘贴,只是让PHP直接与Redis通信.AUTH.但是对于这个演示,您将把SID ramom807vt1io3sqvmc8m4via1放入redis,然后授予访问权限.

alfred@alfred-laptop:~/database/redis-2.2.0-rc4/src$ ./redis-cli 
redis> sadd sid ramom807vt1io3sqvmc8m4via1
(integer) 1
redis> 
Run Code Online (Sandbox Code Playgroud)

  • 这种方法不会容易受到中间人攻击或模仿的影响 - 假设客户端会将其Cookie SID值更改为其他一些SID(在当前上下文中也是有效的),因此他会被模仿作为其他用户? (2认同)
  • @Alfred,你应该真的加入socket.io google组并用redis帮助他们,显然redis memorystore将集成在0.8中!还有,所有redis帮助都很好,我看到你参与了很多答案!奖励! (2认同)

rco*_*ode 8

请记住,会话只是存储在php会话目录中的文件.node.js从cookie中获取会话ID并检查会话目录中是否确实存在会话ID也不成问题.要获取sessions目录的路径,请参阅php.ini中的session.save_path指令.