我想在一个NodeJs应用程序和一个PHP使用的应用程序之间共享服务器会话Redis。我从这个要点中提取了大部分代码。
NodeJs
PHP
Redis
NodeJs代码:
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, ' ') ); });
它输出:
{ "cookie": { "originalMaxAge": null, "expires": null, "httpOnly": true, "path": "/" }, "passport": {}, "nodejs": "node.js!" }
PHP代码(我使用redis-session-php和Predis):
require('redis-session-php/redis-session.php'); RedisSession::start(); $_SESSION['php'] = 'php'; if (!isset($_SESSION["cookie"])) { $_SESSION["cookie"] = array(); } var_dump($_SESSION);
array(2) { ["php"] => string(3) "php" ["cookie"] => array(0) { } }
问题: 我希望两个会话看起来都一样,但是却不一样(应用程序在同一域上运行)。使用set()from Predis\Client作品设置值(但这些值不会在会话变量上)。我使用和找到了我认为可以工作的代码,但我认为这会使代码过于复杂。set()``get()
set()
Predis\Client
set()``get()
你知道我在做什么错吗?
我是要旨的作者。该代码一直有效,直到express-session开始强制签名的cookie并开始以其他方式实现它们。
express-session
我已更新要点,以使用最新版本的express-session。为了方便起见,下面是要点的副本:
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>"; ?>