в узле js не виден сеанс php (redis)

1

Я использую сервер Redis для обмена сеансом между Php и узлами js. Для клиента Node js используйте "connect-redis", а для клиента php используйте redis-session-php и Predis. Я взял большую часть кода от gist обновленной версии на стеке (от правильного ответа).

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>";

?>

Проблема заключается в следующем: при первом выполнении "php файла" выполните "страница узла узла js" - "страница узла узла js" не увидели создание сеанса из "php файла". Когда наоборот (сначала выполните "узел js-сервера узла", затем выполните "php файл") переменные сеанса увидели на обеих страницах

результат app.php

[]{
    "php": "Hello from PHP",
    "cookie": []
}

узел узла js результатов (http://127.0.0.1:8080)

{
    "cookie": {
        "originalMaxAge": null,
        "expires": null,
        "httpOnly": true,
        "path": "/"
    },
    "nodejs": "Hello from node.js!"
}
Теги:
session

2 ответа

1
Лучший ответ

Я решаю эту проблему из этой статьи: общий ресурс сеанса PHP и Node.JS с использованием Redis

app.js

var app = require("http").createServer(handler),
    fs = require("fs"),
    redis = require("redis"),
    co = require("./cookie.js");

app.listen(443);

//On client incomming, we send back index.html
function handler(req, res) {
    //Using php session to retrieve important data from user
    var cookieManager = new co.cookie(req.headers.cookie);

    //Note : to specify host and port : new redis.createClient(HOST, PORT, options)
    //For default version, you don't need to specify host and port, it will use default one
    var clientSession = new redis.createClient();
    console.log('cookieManager.get("PHPSESSID") = ' + cookieManager.get("PHPSESSID"));
    clientSession.get("sessions/" + cookieManager.get("PHPSESSID"), function(error, result) {
        console.log("error : " + result);
        if(error) {
            console.log("error : " + error);
        }
        if(result != null) {
            console.log("result exist");
            console.log(result.toString());
        } else {
            console.log("session does not exist");
        }
    });

    //clientSession.set("sessions/" + cookieManager.get("PHPSESSID"), '{"selfId":"salamlar22", "nodejs":"salamlar33"}');
}

cookie.js

//Directly send cookie to system, if it node.js handler, send :
//request.headers.cookie
//If it socket.io cookie, send :
//client.request.headers.cookie
module.exports.cookie = function(co){
    this.cookies = {};
    co && co.split(';').forEach(function(cookie){
        var parts = cookie.split('=');
        this.cookies[parts[0].trim()] = (parts[1] || '').trim();
    }.bind(this));

    //Retrieve all cookies available
    this.list = function(){
        return this.cookies;
    };

    //Retrieve a key/value pair
    this.get = function(key){
        if(this.cookies[key]){
            return this.cookies[key];
        }else{
            return {};
        }
    };

    //Retrieve a list of key/value pair
    this.getList = function(map){
        var cookieRet = {};
        for(var i=0; i<map.length; i++){
            if(this.cookies[map[i]]){
                cookieRet[map[i]] = this.cookies[map[i]];
            }
        }
        return cookieRet;
    };
};

app.php

<?php
include 'redis.php';
session_start();

echo '<pre>';
var_dump($_COOKIE);
echo '</pre>';

echo '$_SESSION["nodejs"] = '.$_SESSION[selfId].'<br>';
$_SESSION[selfId] = 2;
echo '$_SESSION["nodejs"] = '.$_SESSION[selfId].'<br>';
?>

redis.php

<?php
//First we load the Predis autoloader
//echo dirname(__FILE__)."/predis-1.0/src/Autoloader.php";
require(dirname(__FILE__)."/redis-session-php/modules/predis/src/Autoloader.php");
//Registering Predis system
Predis\Autoloader::register();

/**
 * redisSessionHandler class
 * @class           redisSessionHandler
 * @file            redisSessionHandler.class.php
 * @brief           This class is used to store session data with redis, it store in json the session to be used more easily in Node.JS
 * @version         0.1
 * @date            2012-04-11
 * @author          deisss
 * @licence         LGPLv3
 *
 * This class is used to store session data with redis, it store in json the session to be used more easily in Node.JS
 */
class redisSessionHandler{
    private $host = "127.0.0.1";
    private $port = 6379;
    private $lifetime = 0;
    private $redis = null;

    /**
     * Constructor
    */
    public function __construct(){
        $this->redis = new Predis\Client(array(
            "scheme" => "tcp",
            "host" => $this->host,
            "port" => $this->port
        ));
        session_set_save_handler(
            array(&$this, "open"),
            array(&$this, "close"),
            array(&$this, "read"),
            array(&$this, "write"),
            array(&$this, "destroy"),
            array(&$this, "gc")
        );
    }

    /**
     * Destructor
    */
    public function __destruct(){
        session_write_close();
        $this->redis->disconnect();
    }

    /**
     * Open the session handler, set the lifetime ot session.gc_maxlifetime
     * @return boolean True if everything succeed
    */
    public function open(){
        $this->lifetime = ini_get('session.gc_maxlifetime');
        return true;
    }

    /**
     * Read the id
     * @param string $id The SESSID to search for
     * @return string The session saved previously
    */
    public function read($id){
        $tmp = $_SESSION;
        $_SESSION = json_decode($this->redis->get("sessions/{$id}"), true);
        if(isset($_SESSION) && !empty($_SESSION) && $_SESSION != null){
            $new_data = session_encode();
            $_SESSION = $tmp;
            return $new_data;
        }else{
            return "";
        }
    }

    /**
     * Write the session data, convert to json before storing
     * @param string $id The SESSID to save
     * @param string $data The data to store, already serialized by PHP
     * @return boolean True if redis was able to write the session data
    */
    public function write($id, $data){
        $tmp = $_SESSION;
        session_decode($data);
        $new_data = $_SESSION;
        $_SESSION = $tmp;

        $this->redis->set("sessions/{$id}", json_encode($new_data));
        $this->redis->expire("sessions/{$id}", $this->lifetime);
        return true;
    }

    /**
     * Delete object in session
     * @param string $id The SESSID to delete
     * @return boolean True if redis was able delete session data
    */
    public function destroy($id){
        return $this->redis->delete("sessions/{$id}");
    }

    /**
     * Close gc
     * @return boolean Always true
    */
    public function gc(){
        return true;
    }

    /**
     * Close session
     * @return boolean Always true
    */
    public function close(){
        return true;
    }
}

new redisSessionHandler();
?>
1

Вероятно, вы столкнулись с проблемой перекрестного домена. Если вы используете PHP и Node в другом адресе или порту, чем PHP (и, вероятно, вы есть), HTML не будет делиться Cookies между запросами, которые идут в другой домен, он будет хранить отдельные копии в каждом домене.

Если вы используете субдомены (например, ваш PHP в URL-адресе, например app1.mydomain.com и ваш NodeJS, запущенный в app2.mydomain.com), вы можете поделиться своими настройками cookie, чтобы их настроить/прочитать, используя основной путь cookie домена (mydomain.com).

Здесь есть хорошая информация по этой теме:

Использование Express и Node, как поддерживать сеанс по субдоменам/хост-узлам.

Позвольте мне, если вам нужна дополнительная информация, или если ваша проблема не совсем такая.

  • 0
    Я использую тот же домен. php на сервере apache (порт 80) и js-сервер узла в одном домене (порт 443)
  • 0
    Они находятся в разных портах (один - 80, а другой - 443), и если какая-либо платформа (php или узел) установит параметр порта cookie, они не будут считаться живущими в одном домене (по крайней мере, для вашего браузера). Но я думаю о еще одной проблеме в вашем случае: один - HTTP, а другой - HTTPS. Совместное использование файлов cookie между незащищенными и защищенными соединениями требует дополнительной настройки в вашем коде (и сделает ваше приложение более уязвимым). И еще одна вещь: если вы вызываете один URL-адрес с помощью localhost, а другой - с помощью 127.0.0.1, они не будут использовать одни и те же файлы cookie. Как видите, проблему нужно проследить

Ещё вопросы

Сообщество Overcoder
Наверх
Меню