2015-01-15 2 views
7

Ich möchte die Serversitzung zwischen einer NodeJs App und einer PHP App mit Redis teilen. Ich habe den Großteil des Codes von diesem gist genommen.Wie kann die Sitzung zwischen NodeJs und PHP mit Redis geteilt werden?

NodeJS Code:

app.use(session({ 
    store: new RedisStore({prefix: 'session:php:'}), 
    name: 'PHPSESSID', 
    secret: 'node.js' 
})); 

app.use(function(req, res, next) { 
    req.session.nodejs = 'node.js!'; 
    res.send(JSON.stringify(req.session, null, ' ')); 

}); 

Und es gibt:

{ 
    "cookie": { 
     "originalMaxAge": null, 
     "expires": null, 
     "httpOnly": true, 
     "path": "/" 
    }, 
    "passport": {}, 
    "nodejs": "node.js!" 
} 

PHP-Code (ich benutze redis-session-php und Predis):

require('redis-session-php/redis-session.php'); 
RedisSession::start(); 

$_SESSION['php'] = 'php'; 

if (!isset($_SESSION["cookie"])) { 
    $_SESSION["cookie"] = array(); 
} 

var_dump($_SESSION); 

Und es gibt:

array(2) { 
    ["php"] => string(3) "php" 
    ["cookie"] => array(0) { } 
} 

Das Problem: Ich würde erwarten, dass beide Sitzungen gleich aussehen, aber sie nicht (die App wird auf der gleichen Domäne ausgeführt). Das Setzen der Werte mit set() von Predis\Client funktioniert (aber die Werte werden nicht auf der Sitzungsvariablen sein). Ich fand this code, dass ich denke, würde funktionieren, mit set() und get(), aber ich denke, dass es den Code zu kompliziert würde.

Wissen Sie, was ich falsch mache?

+0

etwas scheint mit dem die PHP-redis Modul fischig. Ich würde erwarten, einige Konfigurationsoptionen für die Verbindung zu Redis zu sehen. kannst du uns die config für die PHP Redis zeigen (hauptsächlich was du in den Konstruktor übergibst) – geggleto

+0

Ich übergebe es nichts, standardmäßig geht es davon aus, dass wenn keine Argumente übergeben werden '127.0.0.1' und '6379' als Standard Host angenommen wird und Port mit einem Verbindungs-Timeout von 5 Sekunden –

+0

Wll in Ihrem node.js übergeben Sie einen geheimen Schlüssel ... ich sehe nicht die Option in Ihrem Code für php. könnte es sein, dass es keine Verbindung zu demselben Redis-Speicher? – geggleto

Antwort

12

Ich bin der Autor des Kerns. Der Code funktionierte, bis express-session begann, signierte Cookies zu erzwingen und mit der Implementierung auf andere Weise zu beginnen.

Ich habe das Wesentliche aktualisiert, um mit der neuesten Version von express-session zu arbeiten. Eine Kopie des Wesentlichen folgt der Einfachheit halber:

app.js:

var express = require('express'), 
    app = express(), 
    cookieParser = require('cookie-parser'), 
    session = require('express-session'), 
    RedisStore = require('connect-redis')(session); 

app.use(express.static(__dirname + '/public')); 
app.use(function(req, res, next) { 
    if (~req.url.indexOf('favicon')) 
    return res.send(404); 
    next(); 
}); 
app.use(cookieParser()); 
app.use(session({ 
    store: new RedisStore({ 
    // this is the default prefix used by redis-session-php 
    prefix: 'session:php:' 
    }), 
    // use the default PHP session cookie name 
    name: 'PHPSESSID', 
    secret: 'node.js rules', 
    resave: false, 
    saveUninitialized: false 
})); 
app.use(function(req, res, next) { 
    req.session.nodejs = 'Hello from node.js!'; 
    res.send('<pre>' + JSON.stringify(req.session, null, ' ') + '</pre>'); 
}); 

app.listen(8080); 

app.php:

<?php 
// this must match the express-session `secret` in your Express app 
define('EXPRESS_SECRET', 'node.js rules'); 

// ==== BEGIN express-session COMPATIBILITY ==== 
// this id mutator function helps ensure we look up 
// the session using the right id 
define('REDIS_SESSION_ID_MUTATOR', 'express_mutator'); 
function express_mutator($id) { 
    if (substr($id, 0, 2) === "s:") 
    $id = substr($id, 2); 
    $dot_pos = strpos($id, "."); 
    if ($dot_pos !== false) { 
    $hmac_in = substr($id, $dot_pos + 1); 
    $id = substr($id, 0, $dot_pos); 
    } 
    return $id; 
} 
// check for existing express-session cookie ... 
$sess_name = session_name(); 
if (isset($_COOKIE[$sess_name])) { 
    // here we have to manipulate the cookie data in order for 
    // the lookup in redis to work correctly 

    // since express-session forces signed cookies now, we have 
    // to deal with that here ... 
    if (substr($_COOKIE[$sess_name], 0, 2) === "s:") 
    $_COOKIE[$sess_name] = substr($_COOKIE[$sess_name], 2); 
    $dot_pos = strpos($_COOKIE[$sess_name], "."); 
    if ($dot_pos !== false) { 
    $hmac_in = substr($_COOKIE[$sess_name], $dot_pos + 1); 
    $_COOKIE[$sess_name] = substr($_COOKIE[$sess_name], 0, $dot_pos); 

    // https://github.com/tj/node-cookie-signature/blob/0aa4ec2fffa29753efe7661ef9fe7f8e5f0f4843/index.js#L20-L23 
    $hmac_calc = str_replace("=", "", base64_encode(hash_hmac('sha256', $_COOKIE[$sess_name], EXPRESS_SECRET, true))); 
    if ($hmac_calc !== $hmac_in) { 
     // the cookie data has been tampered with, you can decide 
     // how you want to handle this. for this example we will 
     // just ignore the cookie and generate a new session ... 
     unset($_COOKIE[$sess_name]); 
    } 
    } 
} else { 
    // let PHP generate us a new id 
    session_regenerate_id(); 
    $sess_id = session_id(); 
    $hmac = str_replace("=", "", base64_encode(hash_hmac('sha256', $sess_id, EXPRESS_SECRET, true))); 
    // format it according to the express-session signed cookie format 
    session_id("s:$sess_id.$hmac"); 
} 
// ==== END express-session COMPATIBILITY ==== 



require('redis-session-php/redis-session.php'); 
RedisSession::start(); 

$_SESSION["php"] = "Hello from PHP"; 
if (!isset($_SESSION["cookie"])) 
    $_SESSION["cookie"] = array(); 

echo "<pre>"; 
echo json_encode($_COOKIE, JSON_PRETTY_PRINT); 
echo json_encode($_SESSION, JSON_PRETTY_PRINT); 
echo "</pre>"; 

?> 
+0

Diese Zeile '$ _COOKIE [$ sess_name] = substr ($ _COOKIE [$ sess_name], 0, $ dot_pos);' wird den Sitzungscookie nicht gleich "" machen? " –

+0

No.' express-session's Cookie-Format ist 's: <32-byte id>. <32-Byte-ID hmac>'. Also ist die ganze Zeile macht nur den Session-Cookie-Wert auf die 32-Byte-ID Teil. Der Code könnte wahrscheinlich ein wenig vereinfacht werden, seit ich enthalten die "express_mutator" -Funktion, aber der hmac-Wert sollte noch verifiziert werden. – mscdex

+0

Aber wenn ich zwischen PHP und NodeJs umschalte, wird jedes Mal eine neue Sitzungs-ID generiert, weil einer von ihnen den Cookie als 's: <32-byte id>. <32-Byte-ID hmac>' und den anderen als '<32-byte id>', richtig setzt ? Wie kann ich das mit 2 separaten Cookies beheben? –

Verwandte Themen