简体   繁体   English

如何在node.js服务器上的PHP Web服务器和Socket.io之间创建握手?

[英]How to create a handshake between PHP web server and Socket.io on node.js server?

I have a websocket running on node.js 4.0 on server 10.0.4.18 at port 8020. I implemented my websocket using socket.io v1.3, express, and express-session. 我在服务器10.0.4.18上的端口8020上运行了node.js 4.0上的websocket。我使用socket.io v1.3,express和express-session实现了我的websocket。

Project Definition 项目定义

I need to be able to create a session in socket.io for every user that connects to it from a PHP application. 我需要能够在socket.io中为从PHP应用程序连接到它的每个用户创建一个会话。 After the user send the first HTTP request, I will authenticate them using a token that will be passed from PHP to socket.io along with the HTTP request. 在用户发送第一个HTTP请求之后,我将使用将从PHP传递到socket.io以及HTTP请求的令牌对它们进行身份验证。

After the user is authenticated, I need to save some personal data inside socket.io session to reuse later. 用户通过身份验证后,我需要在socket.io会话中保存一些个人数据,以便以后重用。 Every time the user refresh the PHP application, socket.io will need to know the session data that is already created. 每次用户刷新PHP应用程序时,socket.io都需要知道已创建的会话数据。

Problem 问题

Every time the user reloads/refreshed the PHP page "where he/she connected from", the session data are lost. 每次用户重新加载/刷新PHP页面“他/她从哪里连接”时,会话数据都会丢失。 The server fails to know that connection belong to session XYZ which is previously created created. 服务器无法知道该连接属于先前创建的会话XYZ。

I am not sure how to create a handshake between PHP and node.js where the two server can exchange a unique data to tie the socket.io session to. 我不确定如何在PHP和node.js之间创建握手,其中两个服务器可以交换唯一数据以将socket.io会话绑定到。

Very close look at the problem 仔细看看这个问题

I opened this link https://10.0.4.18:8020/set/MikeA in my browser. 我在浏览器中打开了这个链接https://10.0.4.18:8020/set/MikeA "This created a session for me directly from node.js per the route code" “这根据路由代码直接从node.js为我创建了一个会话”

Then I connected to the websocket using PHP, now I can see that the session sticks with no problem! 然后我使用PHP连接到websocket,现在我可以看到会话没有问题! I was able to open multiple tabs in the browser and the same session is there as expected. 我能够在浏览器中打开多个选项卡,并且会按预期进行相同的会话。

The reason it worked this time is because the url https://10.0.4.18:8020/set/MikeA established a session and tied it between my browser and the session and from there I was able to read/write my session from socket.io using express-socket.io-session package https://www.npmjs.com/package/express-socket.io-session . 它这次工作的原因是因为网址https://10.0.4.18:8020/set/MikeA建立了一个会话并将其绑定在我的浏览器和会话之间,从那里我能够从socket读取/写入我的会话。我使用express-socket.io-session包https://www.npmjs.com/package/express-socket.io-session

But if I do not create the session using the url manually the session will only be good for one page load only. 但是如果我不手动使用url创建会话,则会话仅适用于一个页面加载。 And every time the page is reloaded the session is destroyed like it never existed! 每次重新加载页面时,会话都会被破坏,就像它从未存在过一样!

Question

I need to develop the same behavior when connection to the websocket via https://10.0.4.18:8020/set/MikeA when connecting from the socket.io. 当从socket.io连接时,我需要通过https://10.0.4.18:8020/set/MikeA连接到websocket时开发相同的行为。

How can I establish a handshake between PHP server and socket.io where the two servers can tie the session data to the correct user every time the PHP page is reloaded or a new browser's tab is opened? 如何在PHP服务器和socket.io之间建立握手,其中两个服务器可以在每次重新加载PHP页面或打开新的浏览器选项卡时将会话数据绑定到正确的用户?

Here is my websocket code 这是我的websocket代码

var app = require('express')(),
    https = require('https'),
    fs = require('fs'),
    session = require('express-session'),
    sharedsession = require("express-socket.io-session"),
    fileStore = require('session-file-store')(session),
    base64url = require('base64url'),
    cookieParser = require("cookie-parser"),
    env = require('./modules/config');


var server = https.createServer(
    {
        key: fs.readFileSync('certs/key.pem'),
        cert: fs.readFileSync('certs/cert.pem')
    }, app).listen(env.socket.port, env.socket.host, function () {
    console.log('\033[2J');
    console.log('Websocket is running at https://%s:%s', server.address().address, server.address().port);
});

var io = require('socket.io')(server);

var icwsReq = require('./modules/icws/request.js'),
    icwsConn = require('./modules/icws/connection.js'),
    icwsInter = require('./modules/icws/interactions.js'),
    sessionValidator = require('./modules/validator.js');

var icwsRequest = new icwsReq();
var sessionChecker = new sessionValidator();

var sessionStoreFile = new fileStore({path: './tmp/sessions'});

var clients = {};

var sessionOptions = {
        store: sessionStoreFile,
        secret: env.session.secret,
        name: env.session.name,
        rolling: true,
        saveUninitialized: false,
        resave: true,
        unset: 'keep',
        cookie: {
            maxAge: 60 * 60 * 1000
        }
    };

var sessionMiddleware = session(sessionOptions);

app.use(sessionMiddleware); // session support for the app


//Set access control headers on every express route.
app.use(function (req, res, next){
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
    next();
});


// Use shared session middleware for socket.io
io.use(sharedsession(sessionMiddleware, {
    autoSave: true
})); 

//Middleware for authorizing a user before establishing a connection
io.use(function(socket, next) {

    var myIP = socket.request.socket.remoteAddress || '';
    var token = socket.handshake.query.tokenId || '';
    var session = socket.handshake.session || {};

    if(!session && !token){
        console.log('Log: No session and no token!');
        return next(new Error('No tken/session found'));
    }

    if(!token){
        console.log('Log: token was not found');
        return next(new Error('Token not found'));
    }

    //SessionID should be defined on a page reload
    console.log('IP Address: ' + myIP + '      SessionID: ' + socket.handshake.sessionID);

    //allow any user that is authorized
    if(session && session.autherized && token == session.token){
        console.log('Log: you are good to go');
        return next(new Error('You are good to go'));
    }

    //if the client changed their token "client logged out"
    //terminate the open session before opening a new one
    if (session.autherized && token != session.token){

    var decodedToken = base64url.decode(token);

    sessionChecker.validateData(decodedToken, myIP, env.session.duration, function(isValid, icws){

        if(!isValid){
            console.log('Log: token could not be validated!');
            return next(new Error('Token could not be validated!'));
        }

        session.authorized = true;
        session.icwsServer = icws.host;
        session.icwsPort = icws.port;
        session.token = token;
        session.icwsSessionId = null;
        session.icwsToken = null;

        icwsRequest.setConnection(icws.host, icws.port);
        var icwsConnection = new icwsConn(icwsRequest);

        session.save(function(){
            console.log('Log: new connection to websocket!');
            return next();
        });
    });

});


io.on('connection', function (socket) { 

    console.log('Connection is validated and ready for action!');

    var socketId = socket.id;

    if(!socket.handshake.sessionID){
        console.log('sessionId was not found');
        return false;
    }

    var sessionID = socket.handshake.sessionID;
    var userCons = clients[sessionID] || [];

    //Add this socket to the user's connection
    if(userCons.indexOf(socketId) == -1){
        userCons.push(socketId);
    }

    clients[sessionID] = userCons;

    socket.on('chat', function(msg){

        for (var key in clients[sessionID]) {
          if (clients[sessionID].hasOwnProperty(key)) {
            var id = clients[sessionID][key];
            console.log('Client Said: ' + msg);
            io.to(id).emit('chat', {message: 'Server Said: ' + msg});
          }
        }
    });


    socket.on('disconnect', function(msg){
        console.log('Closing sessionID: ' + sessionID);
        var userCons = clients[sessionID] || [];

        var index = userCons.indexOf(socketId);

        if(index > -1){
            userCons.splice(index, 1);
            console.log('Removed Disconnect Message: ' + msg);
        } else {
            console.log('Disconnect Message: ' + msg);
        }

    }); 

    socket.on('error', function(msg){
        console.log('Error Message: ' + msg);
    }); 

});


app.get('/', function (req, res) {
    res.send('welcome: ' + req.sessionID);
});

app.get('/read', function (req, res) {
    res.send('welcome: ' + req.session.name);
});

app.get('/set/:name', function (req, res) {
    req.session.name = req.params.name;
    res.send('welcome: ' + req.session.name);
});

Here is how I connect to the websocket from PHP server 以下是我从PHP服务器连接到websocket的方法

<!doctype html>
<html lang="en-US">
  <head>
    <title>Socket.IO chat</title>
    <meta charset="utf-8">
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>

    <script src="https://10.0.4.18:8020/socket.io/socket.io.js"></script>
    <script type="text/javascript" src="/js/jquery-2.1.0.min.js"></script>
    <script>

        $(function(){
            var socket = io.connect('https://10.0.4.18:8020', {secure: true, port: 8020,  query : 'PHP generated token that will be used to authenticate the user from node.js'});

           //When the "send" button is clicked
            $('#f').click(function(e){
                e.preventDefault();
                var message = $('#m').val().trim();
                if( message  == ''){
                    return false;
                }

                socket.emit('chat', message);
                $('#m').val('');
            });

            socket.on('chat', function(msg){
                $('#messages').append($('<li>').text(msg.message));
            });

        });

    </script>

  </head>
  <body>
    <ul id="messages"></ul>
    <form action="" id="f">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>

Store the token in the browser and send it along with every request from the php, with an authorization bearer which looks like : 将令牌存储在浏览器中,并将其与来自php的每个请求一起发送,其授权持有者如下所示:

Authorization: Bearer token

So everytime the node.js server get's an request you can compare the token to which user corresponds and get the data. 因此,每当node.js服务器获得请求时,您都可以比较用户对应的令牌并获取数据。

You can store the relationship between the userid and the token with an expiry date in a table and refresh the token on every login. 您可以将userid和令牌之间的关系存储在表中的到期日期,并在每次登录时刷新令牌。

Also if you don't want to use a table, you can store the data in the token, with JWT 此外,如果您不想使用表,可以使用JWT将数据存储在令牌中

You can find more info here: 你可以在这里找到更多信息:

http://jwt.io/ http://jwt.io/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM