Аутентифицировать пользователя для socket.io/nodejs - PullRequest
39 голосов
/ 28 июня 2011

У меня есть логин php, пользователь вводит имя пользователя / пароль, он проверяет mysql db на информацию о логине. Если аутентифицировано, сеанс создается через php, и пользователь теперь может получить доступ к системе через сеанс php. У меня вопрос, как только они проходят аутентификацию через php / session, каков будет процесс авторизации пользователя, чтобы увидеть, если у него есть права на вход в систему для доступа к серверу nodejs с socket.io? Я не хочу, чтобы человек имел доступ к функции / серверу nodejs / socket.io, если он не прошел аутентификацию через логин php.

Ответы [ 4 ]

62 голосов
/ 28 июня 2011

Обновление

Требования:

  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);
});

PHP

php с аутентификацией openid => http://dl.dropbox.com/u/314941/6503745/php.tar.gz

После входа в систему вы должны перезагрузить client.php для аутентификации


ps: мне действительно не нравится идея создания еще одного пароля, который, вероятно, будет небезопасным.Я бы посоветовал вам взглянуть на openID (например, через Google ), Facebook Connect (просто назовите несколько вариантов).

Мой вопрос: как только они проходят аутентификацию через php / session, каков будет процесс аутентификации пользователя, чтобы увидеть, имеют ли они права на вход в систему для доступа к серверу nodejs с socket.io?Я не хочу, чтобы человек имел доступ к функции / серверу nodejs / socket.io, если он не прошел аутентификацию через логин php.

Добавьте уникальный session_id в список /набор разрешенных идентификаторов, чтобы socket.io мог авторизовать (поиск функции авторизации) этого соединения.Я бы позволил PHP общаться с node.js, используя redis , потому что это будет молниеносно / AWESOME :).Прямо сейчас я подделываю сообщение 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

Запустить 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.Конечно, обычно вы не выполняете копирование, а просто позволяете 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> 
8 голосов
/ 28 июня 2011

Помните, что сессии - это просто файлы, хранящиеся в каталоге сессий php. Для node.js не составит проблемы получить идентификатор сеанса из файла cookie, а затем проверить, существует ли сеанс в каталоге сеансов. Чтобы узнать путь к каталогу сессий, обратитесь к директиве session.save_path в вашем php.ini.

0 голосов
/ 12 апреля 2018

Я просматривал решения здесь и решил попробовать то, что сказал rcode, потому что это казалось намного проще, чем гигантская стена кода, которая приняла ответ.

В итоге все получилось, и сделать это довольно просто.

В итоге я установил несколько зависимостей, которых я хотел избежать, но относительно легко сделать с узлом.

Введите в консоли следующее:

npm install cookie

npm install php-unserialize

Это решение использует файлы сеанса на машине - вам не нужно изменять эту строку.

session.save_handler = files

^ Так должно быть в вашем файле php.ini (по умолчанию).

(Люди предлагали использовать memcache, но переключение на эту систему казалось головной болью.)

Вот супер простой код для извлечения данных сеанса:

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);
                }
            });
        }
    }
}

Результаты:

Results

Редактировать: я просто хотел добавить, что может быть проще просто заставить PHP сообщать серверу Node.js, когда кто-то входит в систему и передает туда учетные данные.

Я объясняю, как это легко сделать, в другом ответе.

https://stackoverflow.com/a/49864533/1274820

0 голосов
/ 19 июня 2012

Вот код 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...