php - rooms - Autentica el usuario para socket.io/nodejs
socket.io php (4)
Actualizar
Requisitos:
- Primero tienes redis en ejecución.
- Luego enciende socket.io.
- Finalmente cargar / alojar PHP (tiene dependencias en el archivo).
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
php con autenticación openid => http://dl.dropbox.com/u/314941/6503745/php.tar.gz
Después del inicio de sesión, debe volver a cargar client.php
para autenticarse
ps: Realmente no me gusta el concepto de crear incluso otra contraseña que probablemente sea insegura. Te aconsejaría que openID un vistazo a openID (a través de Google por ejemplo), Facebook Connect (solo nombra algunas opciones).
Mi pregunta es una vez que se autentiquen a través de php / session ¿cuál sería el proceso para autenticar al usuario para ver si tienen los permisos de inicio de sesión correctos para acceder a un servidor de nodejs con socket.io? No quiero que la persona tenga acceso a la función / servidor nodejs / socket.io a menos que se hayan autenticado a través del inicio de sesión de php.
Agregue el session_id exclusivo a una lista / conjunto de identificadores permitidos para que socket.io pueda authorize (buscar la función de autorización) esa conexión. Dejaría que PHP se comunique con node.js usando redis porque va a ser muy rápido / IMPRESIONANTE :). En este momento estoy fingiendo la comunicación PHP de redis-cli
Instalar Redis
Descargar redis => En este momento, la versión estable se puede descargar de: 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
Inicie Redis-server
alfred@alfred-laptop:~/6502031/redis-2.2.11/src$ ./redis-server
Socket.io
dependencias npm
Si npm
no está instalado, primero visite http://npmjs.org
npm install express
npm install socket.io
npm install redis
listando las dependencias que he instalado y que probablemente también deberías instalar en caso de incompatibilidad según npm ls
alfred@alfred-laptop:~/node/socketio-demo$ npm ls
/home/alfred/node/socketio-demo
├─┬ [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ └── [email protected]
├── [email protected]
├── [email protected]
└─┬ [email protected]
├── [email protected]
└── [email protected]
Code
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'');
});
Para ejecutar el servidor solo ejecuta el 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>
Autenticación de prueba
Cuando carga la página web (archivo PHP) desde su navegador web, se muestra el mensaje access denied
, pero cuando agrega el session_id
también se muestra en el navegador para redis server, se mostrará el mensaje de access granted
. Por supuesto, normalmente no harías ninguna copia pegando, sino que simplemente permites que PHP se comunique directamente con Redis. . Pero para esta demostración, colocará SID ramom807vt1io3sqvmc8m4via1
en redis, después de lo cual se ha otorgado acceso.
alfred@alfred-laptop:~/database/redis-2.2.0-rc4/src$ ./redis-cli
redis> sadd sid ramom807vt1io3sqvmc8m4via1
(integer) 1
redis>
Tengo un inicio de sesión de php, el usuario ingresa un nombre de usuario / contraseña, comprueba el mysql db contra la información de inicio de sesión. Si se autentica, se crea una sesión a través de php y el usuario ahora puede acceder al sistema con la sesión php. Mi pregunta es una vez que se autentican a través de php / session ¿cuál sería el proceso para autorizar al usuario a ver si tienen los permisos de inicio de sesión correctos para acceder a un servidor nodejs con socket.io? No quiero que la persona tenga acceso a la función / servidor nodejs / socket.io a menos que se hayan autenticado a través del inicio de sesión de php.
Aquí está el código unserialize y utf8 si lo deseas también, originalmente derivado de phpjs.org - tuve que editarlo un poco para que funcione con node.js, así que busca y compara si quieres
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:[email protected])
// + 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;
Estuve revisando las soluciones aquí y decidí dar lo que decía el rcode, porque parecía mucho más fácil que la gigantesca pared de código aceptada.
Terminó funcionando bien y es bastante fácil de hacer.
Terminé instalando algunas dependencias que quería evitar, pero es relativamente fácil de hacer con el nodo.
Escriba lo siguiente en la consola:
npm install cookie
npm install php-unserialize
Esta solución usa los archivos de sesión en la máquina; no debería tener que cambiar esta línea.
session.save_handler = files
^ Debería ser así en su archivo php.ini (predeterminado).
(La gente sugirió usar Memcache, pero parecía un dolor de cabeza cambiar a ese sistema).
Aquí está el código súper simple para recuperar los datos de la sesión:
var cookie = require(''cookie'');
var fs = require(''fs'');
var phpUnserialize = require(''php-unserialize'');
//This should point to your php session directory.
//My php.ini says session.save_path = "${US_ROOTF}/tmp"
var SESS_PATH = "C:/SomeDirectory/WhereYourPHPIs/tmp/";
io.on(''connection'', function(socket) {
//I just check if cookies are a string - may be better method
if(typeof socket.handshake.headers.cookie === "string") {
var sid = cookie.parse(socket.handshake.headers.cookie);
if(typeof sid.PHPSESSID === "undefined") {
console.log("Undefined PHPSESSID");
}
else {
console.log("PHP Session ID: " + sid.PHPSESSID);
fs.readFile(SESS_PATH + "sess_" + sid.PHPSESSID, ''utf-8'', function(err,data) {
if(!err) {
console.log("Session Data:");
var sd = phpUnserialize.unserializeSession(data);
console.log(sd);
}
else {
console.log(err);
}
});
}
}
}
Resultados:
Editar: Solo quería agregar que puede ser más fácil simplemente que PHP diga a su servidor Node.js cuando alguien inicia sesión y pasa las credenciales allí.
Explico cómo hacer esto fácilmente en otra respuesta.
https://.com/a/49864533/1274820
Recuerde que las sesiones son solo archivos almacenados en el directorio de sesiones php. No será un problema para node.js obtener la identificación de sesión de la cookie y luego verificar si la sesión realmente existe en el directorio de sesiones. Para obtener la ruta del directorio de sesiones, consulte la directiva session.save_path en su php.ini.