問題描述
我想使用 Redis
在 NodeJs
應(yīng)用程序和 PHP
應(yīng)用程序之間共享服務(wù)器會話.我從這個 gist 中獲取了大部分代碼.
NodeJs 代碼:
app.use(session({商店:新的RedisStore({前綴:'session:php:'}),name: 'PHPSESSID',秘密:'node.js'}));app.use(function(req, res, next) {req.session.nodejs = 'node.js!';res.send(JSON.stringify(req.session, null, ' ') );});
它輸出:
<代碼>{曲奇餅": {原始最大年齡":空,過期":空,httpOnly":真,小路": "/"},護照": {},nodejs":node.js!"}
PHP 代碼(我使用 redis-session-php 和 Predis) :
require('redis-session-php/redis-session.php');RedisSession::start();$_SESSION['php'] = 'php';如果 (!isset($_SESSION["cookie"])) {$_SESSION["cookie"] = array();}var_dump($_SESSION);
它輸出:
array(2) {[php"] =>字符串(3)php"[cookie"] =>數(shù)組(0){}}
問題:我希望兩個會話看起來一樣,但它們不一樣(應(yīng)用程序在同一個域上運行).使用 PredisClient
中的 set()
設(shè)置值有效(但值不會在會話變量上).我發(fā)現(xiàn) 這段代碼我認為可以用, 使用 set()
和 get()
,但我覺得它會使代碼過于復(fù)雜.
你知道我做錯了什么嗎?
我是要點的作者.該代碼一直有效,直到 express-session
開始強制簽名 cookie 并開始以不同的方式實現(xiàn)它們.
我已經(jīng)更新了要點以使用最新版本的 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'))返回 res.send(404);下一個();});app.use(cookieParser());app.use(會話({商店:新的RedisStore({//這是 redis-session-php 使用的默認前綴前綴:'會話:php:'}),//使用默認的 PHP 會話 cookie 名稱name: 'PHPSESSID',秘密:'node.js 規(guī)則',重新保存:假,保存未初始化:假}));app.use(function(req, res, next) {req.session.nodejs = '來自 node.js 的你好!';res.send('<pre>' + JSON.stringify(req.session, null, ' ') + '</pre>');});應(yīng)用程序聽(8080);
app.php:
<?php//這必須與 Express 應(yīng)用程序中的 express-session `secret` 匹配定義('EXPRESS_SECRET','node.js 規(guī)則');//==== 開始快速會話兼容性 ====//這個 id mutator 函數(shù)有助于確保我們查找//使用正確 id 的會話定義('REDIS_SESSION_ID_MUTATOR','express_mutator');函數(shù) express_mutator($id) {if (substr($id, 0, 2) === "s:")$id = substr($id, 2);$dot_pos = strpos($id, ".");如果($dot_pos !== 假){$hmac_in = substr($id, $dot_pos + 1);$id = substr($id, 0, $dot_pos);}返回 $id;}//檢查現(xiàn)有的 express-session cookie ...$sess_name = session_name();如果(isset($_COOKIE[$sess_name])){//這里我們必須操作 cookie 數(shù)據(jù)以便//redis 中的查找工作正常//由于 express-session 現(xiàn)在強制簽署 cookie,我們有//在這里處理...if (substr($_COOKIE[$sess_name], 0, 2) === "s:")$_COOKIE[$sess_name] = substr($_COOKIE[$sess_name], 2);$dot_pos = strpos($_COOKIE[$sess_name], ".");如果($dot_pos !== 假){$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)));如果 ($hmac_calc !== $hmac_in) {//cookie數(shù)據(jù)已被篡改,可自行判斷//你想如何處理這個.對于這個例子,我們將//忽略 cookie 并生成一個新會話 ...未設(shè)置($_COOKIE[$sess_name]);}}} 別的 {//讓 PHP 為我們生成一個新的 idsession_regenerate_id();$sess_id = session_id();$hmac = str_replace("=", "", base64_encode(hash_hmac('sha256', $sess_id, EXPRESS_SECRET, true)));//根據(jù) express-session 簽名的 cookie 格式對其進行格式化session_id("s:$sess_id.$hmac");}//==== 結(jié)束快速會話兼容性 ====require('redis-session-php/redis-session.php');RedisSession::start();$_SESSION["php"] = "你好來自 PHP";如果 (!isset($_SESSION["cookie"]))$_SESSION["cookie"] = array();echo "";回聲 json_encode($_COOKIE, JSON_PRETTY_PRINT);回聲 json_encode($_SESSION, JSON_PRETTY_PRINT);echo "</pre>";?>
I want to share the server session between a NodeJs
app and a PHP
app using Redis
. I took most of the code from this gist.
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, ' ') );
});
And it outputs:
{
"cookie": {
"originalMaxAge": null,
"expires": null,
"httpOnly": true,
"path": "/"
},
"passport": {},
"nodejs": "node.js!"
}
PHP code (I use redis-session-php and Predis) :
require('redis-session-php/redis-session.php');
RedisSession::start();
$_SESSION['php'] = 'php';
if (!isset($_SESSION["cookie"])) {
$_SESSION["cookie"] = array();
}
var_dump($_SESSION);
And it outputs:
array(2) {
["php"] => string(3) "php"
["cookie"] => array(0) { }
}
The problem:
I would expect both sessions to look the same, but they don't ( the app is run on the same domain ). Setting the values with set()
from PredisClient
works (but the values won't be on the session variable). I found this code that I think would work, using set()
and get()
, but I feel that it would overcomplicate the code.
Do you know what I am doing wrong?
I'm the author of the gist. The code worked until express-session
started forcing signed cookies and started implementing them in a different way.
I have updated the gist to work with the latest version of express-session
. A copy of the gist follows for convenience:
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>";
?>
這篇關(guān)于如何使用Redis在NodeJs和PHP之間共享會話?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!