Подтвердить что ты не робот

Аутентифицировать пользователя для socket.io/nodejs

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

4b9b3361

Ответ 1

Update

Требования:

  • Сначала выполните redis.
  • Далее запустите 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

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

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


p.s: Мне действительно не нравится концепция создания еще одного пароля, который, вероятно, будет небезопасным. Я бы посоветовал вам взглянуть на 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

[email protected]:~$ mkdir ~/6502031
[email protected]:~/6502031$ cd ~/6502031/
[email protected]:~/6502031$ tar xfz redis-2.2.11.tar.gz 
[email protected]:~/6502031$ cd redis-2.2.11/src
[email protected]:~/6502031/redis-2.2.11/src$ make # wait couple of seconds

Запустить Redis-сервер

[email protected]:~/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

[email protected]:~/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] 

Код

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, также отображаемый в браузере для повторного сервера, будет показано сообщение access granted. Конечно, вы не будете делать копии, но просто позвольте PHP напрямую общаться с Redis. auth. Но для этой демонстрации вы поместите SID ramom807vt1io3sqvmc8m4via1 в redis, после чего будет предоставлен доступ.

[email protected]:~/database/redis-2.2.0-rc4/src$ ./redis-cli 
redis> sadd sid ramom807vt1io3sqvmc8m4via1
(integer) 1
redis> 

Ответ 2

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

Ответ 3

Я сделал все это с большим трудом и не смог найти для меня жизнь, чтобы затем получить значения хранения сеанса через то, что написал кто-то, поскольку все, что у вас осталось, - это хеш-значение для вашего se. Поэтому я написал эту симпатичную маленькую script, которая анализирует ваши значения сеанса в объекте.

function unserialize_session(str){
    var sessHash, sessHashEnd, sess = {}, serial = '', i =0;
    do {
        sessHash = str.match(/(^|;)([a-zA-Z0-9_-]+)\|/i);
        if (sessHash) {
            str = str.substring(sessHash[0].length);
            serial = str;
            sessHashEnd = serial.match(/(^|;)([a-zA-Z0-9_-]+)\|/i);

            if (sessHashEnd && sessHashEnd[2] && sessHashEnd[2].length > 0) {
                serial = serial.substring(serial.search(new RegExp('(^|;)('+sessHashEnd[2]+')\\|')),0);
                str = str.substring(str.search(new RegExp('(^|;)('+sessHashEnd[2]+')\\|')))
            }

            sess[sessHash[2]] = unserialize(serial);
        }
        if (i++ > 50 ) break;
    } while (sessHash);

    return sess;
}
exports.unserialize_session = unserialize_session;

К сожалению, чтобы получить значения PHP, сеансы должны были работать от MySQL, чтобы получить доступ к ним легко, но эта часть зависит от вас, я думаю!

Ответ 4

Здесь код 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:[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;

Ответ 5

Я искал решения здесь и решил дать то, что сказал 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, когда кто-то входит в систему и передает учетные данные.

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

fooobar.com/info/62069/...