为socket.io/nodejs验证用户
我有一个php登录,用户放入一个用户名/密码,它检查登录信息的MySQL数据库。 如果通过身份验证会话是通过PHP创建的,用户现在可以通过php会话访问系统。 我的问题是,一旦他们通过PHP /会话进行身份验证,将授权用户查看他们是否拥有正确的登录权限以使用socket.io访问nodejs服务器的过程是什么? 我不想让这个人有权访问nodejs / socket.io函数/服务器,除非他们通过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);
});
PHP
与openid身份验证的PHP => http://dl.dropbox.com/u/314941/6503745/php.tar.gz
登录后,您必须重新加载client.php
进行身份验证
ps:我真的不喜欢创建另一个可能会不安全的密码的概念。 我建议你看看openID(通过谷歌例如),Facebook的连接(只是命名一些选项)。
我的问题是,他们一旦通过php / session进行身份验证,将认证用户的过程是什么,以查看他们是否拥有使用socket.io访问nodejs服务器的正确登录权限? 我不想让这个人有权访问nodejs / socket.io函数/服务器,除非他们通过php登录进行了身份验证。
将唯一的session_id添加到允许的id的列表/集合中,以便socket.io可以授权(搜索授权功能)该连接。 我会让PHP使用redis与node.js进行通信,因为这将会闪电般快/真棒:)。 现在我正在伪装来自redis-cli
的PHP通信
安装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
启动Redis服务器
alfred@alfred-laptop:~/6502031/redis-2.2.11/src$ ./redis-server
Socket.io
npm依赖关系
如果npm
尚未安装,请首先访问http://npmjs.org
npm install express
npm install socket.io
npm install redis
列出我已经安装的依赖关系,以及根据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
码
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');
});
运行服务器只需运行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>
测试认证
当您从网络浏览器加载网页(PHP文件)时,会显示消息access denied
,但是当您将浏览器中显示的session_id
添加到redis服务器时,将显示access granted
的消息access granted
。 当然,通常你不会做任何复制粘贴,而只是让PHP直接与Redis进行通信。 。 但是对于这个演示,您将在授予访问权限后将SID ramom807vt1io3sqvmc8m4via1
放入redis中。
alfred@alfred-laptop:~/database/redis-2.2.0-rc4/src$ ./redis-cli
redis> sadd sid ramom807vt1io3sqvmc8m4via1
(integer) 1
redis>
请记住,会话只是存储在php会话目录中的文件。 node.js从cookie中获取会话标识并检查session是否确实存在于sessions目录中不会有问题。 要获取会话目录的路径,请参阅php.ini中的session.save_path指令。
这里是unserialize和utf8的代码,如果你也想要的话,最初是从phpjs.org派生出来的 - 不得不对它进行编辑,使它与node.js一起工作,这样你就可以随时查找并比较你是否想要
function utf8_decode (str_data) {
// http://kevin.vanzonneveld.net
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
// + input by: Aman Gupta
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: Norman "zEh" Fuchs
// + bugfixed by: hitwork
// + bugfixed by: Onno Marsman
// + input by: Brett Zamir (http://brett-zamir.me)
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// * example 1: utf8_decode('Kevin van Zonneveld');
// * returns 1: 'Kevin van Zonneveld'
var tmp_arr = [],
i = 0,
ac = 0,
c1 = 0,
c2 = 0,
c3 = 0;
str_data += '';
while (i < str_data.length) {
c1 = str_data.charCodeAt(i);
if (c1 < 128) {
tmp_arr[ac++] = String.fromCharCode(c1);
i++;
} else if (c1 > 191 && c1 < 224) {
c2 = str_data.charCodeAt(i + 1);
tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = str_data.charCodeAt(i + 1);
c3 = str_data.charCodeAt(i + 2);
tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return tmp_arr.join('');
}
exports.utf8_decode = utf8_decode;
function unserialize (data) {
// http://kevin.vanzonneveld.net
// + original by: Arpad Ray (mailto:arpad@php.net)
// + improved by: Pedro Tainha (http://www.pedrotainha.com)
// + bugfixed by: dptr1988
// + revised by: d3x
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + input by: Brett Zamir (http://brett-zamir.me)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: Chris
// + improved by: James
// + input by: Martin (http://www.erlenwiese.de/)
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: Le Torbi
// + input by: kilops
// + bugfixed by: Brett Zamir (http://brett-zamir.me)
// - depends on: utf8_decode
// % note: We feel the main purpose of this function should be to ease the transport of data between php & js
// % note: Aiming for PHP-compatibility, we have to translate objects to arrays
// * example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}');
// * returns 1: ['Kevin', 'van', 'Zonneveld']
// * example 2: unserialize('a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}');
// * returns 2: {firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'}
var that = this;
var utf8Overhead = function (chr) {
// http://phpjs.org/functions/unserialize:571#comment_95906
var code = chr.charCodeAt(0);
if (code < 0x0080) {
return 0;
}
if (code < 0x0800) {
return 1;
}
return 2;
};
var error = function (type, msg, filename, line) {
console.log('[[[[[[[[[[[[[[[[[[ERROR]]]]]]]]]]]]]]]]]]]','msg:', msg, 'filename:',filename, 'line:',line);
};
var read_until = function (data, offset, stopchr) {
if (stopchr == ';' && !data.match(/;$/)) data += ';';
var buf = [];
var chr = data.slice(offset, offset + 1);
var i = 2;
while (chr != stopchr) {
if ((i + offset) > data.length) {
error('Error', 'Invalid','php.js','126');
}
buf.push(chr);
chr = data.slice(offset + (i - 1), offset + i);
i += 1;
//console.log('i:',i,'offset:',offset, 'data:',data,'chr:',chr,'stopchr:',stopchr);
}
return [buf.length, buf.join('')];
};
var read_chrs = function (data, offset, length) {
var buf;
buf = [];
for (var i = 0; i < length; i++) {
var chr = data.slice(offset + (i - 1), offset + i);
buf.push(chr);
length -= utf8Overhead(chr);
}
return [buf.length, buf.join('')];
};
var _unserialize = function (data, offset) {
var readdata;
var readData;
var chrs = 0;
var ccount;
var stringlength;
var keyandchrs;
var keys;
if (!offset) {
offset = 0;
}
var dtype = (data.slice(offset, offset + 1)).toLowerCase();
var dataoffset = offset + 2;
var typeconvert = function (x) {
return x;
};
switch (dtype) {
case 'i':
typeconvert = function (x) {
return parseInt(x, 10);
};
readData = read_until(data, dataoffset, ';');
chrs = readData[0];
readdata = readData[1];
dataoffset += chrs + 1;
break;
case 'b':
typeconvert = function (x) {
return parseInt(x, 10) !== 0;
};
readData = read_until(data, dataoffset, ';');
chrs = readData[0];
readdata = readData[1];
dataoffset += chrs + 1;
break;
case 'd':
typeconvert = function (x) {
return parseFloat(x);
};
readData = read_until(data, dataoffset, ';');
chrs = readData[0];
readdata = readData[1];
dataoffset += chrs + 1;
break;
case 'n':
readdata = null;
break;
case 's':
ccount = read_until(data, dataoffset, ':');
chrs = ccount[0];
stringlength = ccount[1];
dataoffset += chrs + 2;
readData = read_chrs(data, dataoffset + 1, parseInt(stringlength, 10));
chrs = readData[0];
readdata = readData[1];
dataoffset += chrs + 2;
if (chrs != parseInt(stringlength, 10) && chrs != readdata.length) {
error('SyntaxError', 'String length mismatch','php.js','206');
}
// Length was calculated on an utf-8 encoded string
// so wait with decoding
readdata = utf8_decode(readdata);
break;
case 'a':
readdata = {};
keyandchrs = read_until(data, dataoffset, ':');
chrs = keyandchrs[0];
keys = keyandchrs[1];
dataoffset += chrs + 2;
for (var i = 0; i < parseInt(keys, 10); i++) {
var kprops = _unserialize(data, dataoffset);
var kchrs = kprops[1];
var key = kprops[2];
dataoffset += kchrs;
var vprops = _unserialize(data, dataoffset);
var vchrs = vprops[1];
var value = vprops[2];
dataoffset += vchrs;
readdata[key] = value;
}
dataoffset += 1;
break;
default:
error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype,'php.js','238');
break;
}
return [dtype, dataoffset - offset, typeconvert(readdata)];
};
return _unserialize((data + ''), 0)[2];
}
exports.unserialize = unserialize;
链接地址: http://www.djcxy.com/p/38009.html