web-dev-qa-db-de.com

Benutzer für socket.io/nodejs authentifizieren

Ich habe ein PHP-Login, der Benutzer gibt einen Benutzernamen/ein Passwort ein und überprüft die MySQL-Datenbank mit den Login-Informationen. Wenn authentifiziert eine Sitzung über PHP erstellt wird, kann der Benutzer jetzt über die PHP-Sitzung auf das System zugreifen. Meine Frage ist, sobald sie sich über PHP/Session authentifiziert haben. Wie würde der Benutzer autorisieren, zu sehen, ob er über die richtigen Anmeldeberechtigungen für den Zugriff auf einen nodejs-Server mit socket.io verfügt? Ich möchte nicht, dass die Person Zugriff auf die nodejs/socket.io-Funktion/den Server hat, es sei denn, sie haben sich über das PHP-Login authentifiziert.

34
John

Aktualisieren

Bedarf:

  1. Lass zuerst Redis laufen.
  2. Als nächstes zünden Sie socket.io an.
  3. Zum Schluss upload/host PHP (hat Abhängigkeiten im Archiv).

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 mit Openid-Authentifizierung => http://dl.dropbox.com/u/314941/6503745/php.tar.gz

Nach dem Login müssen Sie client.php erneut laden, um sich zu authentifizieren


p.s: Ich mag das Konzept nicht, auch ein anderes Passwort zu erstellen, das wahrscheinlich unsicher ist. Ich würde Ihnen raten, einen Blick auf openID (über Google zum Beispiel), Facebook Connect (nur einige Optionen) zu werfen.

Meine Frage ist, sobald sie sich authentifiziert haben via php/session was wäre das zur Authentifizierung des Benutzers bei nachsehen, ob sie das richtige Login haben Berechtigungen für den Zugriff auf einen nodejs-Server mit socket.io? Ich will nicht die Person Zugriff auf den nodejs/socket.io Funktion/Server, es sei denn, sie haben authentifiziert über das PHP-Login.

Fügen Sie die eindeutige session_id zu einer Liste/Gruppe von erlaubten IDs hinzu, damit socket.io autorisieren kann (nach Autorisierungsfunktion suchen), diese Verbindung. Ich würde PHP mit node.js über redis kommunizieren lassen, weil das blitzschnell/AWESOME sein wird :). Im Moment fälsche ich die PHP Kommunikation von redis-cli

Installieren Sie Redis

redis herunterladen => Die stabile Version kann jetzt heruntergeladen werden von: 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

Starten Sie den Redis-Server

[email protected]:~/6502031/redis-2.2.11/src$ ./redis-server 

Socket.io

npm Abhängigkeiten

Wenn npm noch nicht installiert ist, besuchen Sie zuerst http://npmjs.org

npm install express
npm install socket.io
npm install redis

auflistung der von mir installierten Abhängigkeiten, die Sie auch bei Inkompatibilität gemäß npm ls installieren sollten

[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] 

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

Um den Server auszuführen, führen Sie einfach node server.js aus.

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>

Testen Sie die Authentifizierung

Wenn Sie die Webseite (PHP-Datei) von Ihrem Webbrowser aus laden, wird die Nachricht access denied angezeigt. Wenn Sie jedoch den session_id hinzufügen, der ebenfalls im Browser zum Redis-Server angezeigt wird, wird die Nachricht access granted angezeigt. Normalerweise würden Sie normalerweise keine Kopie einfügen, sondern lassen Sie PHP direkt mit Redis kommunizieren.auth. Für diese Demo werden Sie jedoch SID ramom807vt1io3sqvmc8m4via1 in redis setzen, nachdem der Zugriff gewährt wurde.

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

Denken Sie daran, dass Sitzungen nur Dateien sind, die im PHP-Sitzungsverzeichnis gespeichert sind. Es ist für knot.js kein Problem, die Sitzungs-ID aus dem Cookie abzurufen und dann zu prüfen, ob die Sitzung wirklich im Sitzungsverzeichnis vorhanden ist. Um den Pfad des Sessions-Verzeichnisses zu erhalten, beziehen Sie sich auf die Direktive session.save_path in Ihrer php.ini.

8
rcode

Hier ist der Code für unserialize und utf8, wenn Sie es auch wollen, ursprünglich abgeleitet von phpjs.org - musste es ein wenig editiert werden, damit es mit node.js funktioniert

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;
0
marksyzm

Ich habe mir die Lösungen hier angesehen und beschlossen, das, was von rcode gesagt wurde, auszuprobieren, weil es so viel einfacher schien, als die gigantische Codewand akzeptierte.

Es hat gut funktioniert und ist ziemlich einfach zu machen.

Am Ende habe ich ein paar Abhängigkeiten installiert, die ich vermeiden wollte, aber mit Knoten relativ einfach zu tun ist.

Geben Sie Folgendes in der Konsole ein:

npm install cookie

npm install php-unserialize

Diese Lösung verwendet die Sitzungsdateien auf dem Computer. Sie sollten diese Zeile nicht ändern müssen.

session.save_handler = files

^ Sollte in Ihrer php.ini-Datei so sein (Standard).

(Die Leute schlugen vor, Memcache zu verwenden, aber es schien Kopfschmerzen zu sein, zu diesem System zu wechseln.)

Hier ist der supereinfache Code zum Abrufen der Sitzungsdaten:

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

Ergebnisse:

 Results

Edit: Ich wollte nur hinzufügen, dass es einfacher sein kann, dass PHP Ihren Node.js-Server benachrichtigt, wenn sich jemand anmeldet und die Anmeldeinformationen dort weitergibt.

Ich erkläre in einer anderen Antwort, wie das geht.

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

0
user1274820