У меня есть websocket, работающий на node.js 4.0 на сервере 10.0.4.18 на порту 8020. Я реализовал свой websocket, используя socket.io v1.3, express и express-session.
Определение проекта
Мне нужно создать сеанс в socket.io для каждого пользователя, который подключается к нему из приложения PHP. После того, как пользователь отправит первый HTTP-запрос, я проведу аутентификацию с помощью токена, который будет передан с PHP на socket.io вместе с HTTP-запросом.
После аутентификации пользователя мне нужно сохранить некоторые личные данные внутри сеанса socket.io для повторного использования позже. Каждый раз, когда пользователь обновляет приложение PHP, socket.io должен знать уже созданные данные сеанса.
проблема
Каждый раз, когда пользователь перезагружает / обновляет страницу PHP «где он / она подключен», данные сеанса теряются. Сервер не знает, что соединение принадлежит сеансу XYZ, который был создан ранее.
Я не уверен, как создать рукопожатие между PHP и node.js, где два сервера могут обмениваться уникальными данными, чтобы связать сессию socket.io.
Очень внимательно посмотрите на проблему
Я открыл эту ссылку https://10.0.4.18:8020/set/MikeA в своем браузере. «Это создало сеанс для меня непосредственно из node.js за код маршрута»
Затем я подключился к websocket с помощью PHP, теперь я вижу, что сессия не имеет проблем! Мне удалось открыть несколько вкладок в браузере, и тот же сеанс там, как и ожидалось.
Причина, по которой она работала на этот раз, – это то, что URL https://10.0.4.18:8020/set/MikeA создал сеанс и связал его между моим браузером и сеансом, а оттуда я смог прочитать / записать сеанс из сокета. io, используя пакет express-socket.io-session https://www.npmjs.com/package/express-socket.io-session .
Но если я не создам сеанс, используя URL-адрес вручную, сеанс будет полезен только для загрузки одной страницы. И каждый раз, когда страница перезагружается, сеанс уничтожается, как никогда не было!
Вопрос
Мне нужно разработать такое же поведение при подключении к websocket через https://10.0.4.18:8020/set/MikeA при подключении через socket.io.
Как я могу установить рукопожатие между сервером PHP и socket.io, где два сервера могут привязывать данные сеанса к правильному пользователю каждый раз, когда страница PHP загружается или открывается вкладка нового браузера?
Вот мой код 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); });
Вот как я подключаюсь к websocket с PHP-сервера
<!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>
Храните маркер в браузере и отправляйте его вместе с каждым запросом от php с носителем авторизации, который выглядит так:
Authorization: Bearer token
Поэтому каждый раз, когда сервер node.js получает запрос, вы можете сравнить токен, которому соответствует пользователь, и получить данные.
Вы можете сохранить связь между идентификатором пользователя и токеном с датой истечения срока действия в таблице и обновить токен при каждом входе в систему.
Также, если вы не хотите использовать таблицу, вы можете хранить данные в токене, используя JWT
Вы можете найти больше информации здесь: