Mam websocket działający na węźle node.js 4.0 na serwerze 10.0.4.18 na porcie 8020. Zaimplementowałem mój websocket przy użyciu socket.io v1.3, express i session-express.Jak utworzyć handshake pomiędzy serwerem PHP a serwerem Socket.io na serwerze node.js?
Definicja projektu
muszę być w stanie stworzyć sesję w socket.io dla każdego użytkownika, który łączy się to z aplikacji PHP. Po wysłaniu przez użytkownika pierwszego żądania HTTP, uwierzytelnię je za pomocą tokena, który zostanie przekazany z PHP do socket.io wraz z żądaniem HTTP.
Po uwierzytelnieniu użytkownika konieczne jest zapisanie niektórych danych osobistych w sesji socket.io w celu ich późniejszego użycia. Za każdym razem, gdy użytkownik odświeży aplikację PHP, socket.io będzie musiał znać dane sesji, które zostały już utworzone.
Problem
Za każdym razem, gdy użytkownik ładuje/odświeżyć stronę PHP „gdzie on/ona połączona z” dane sesji są tracone. Serwer nie wie, że połączenie należy do sesji XYZ, która została wcześniej utworzona.
Nie jestem pewien, jak utworzyć handshake między PHP i node.js, gdzie dwa serwery mogą wymieniać unikatowe dane, aby powiązać sesję socket.io z.
Bardzo blisko spojrzeć na problem
otworzyłem ten link https://10.0.4.18:8020/set/MikeA w przeglądarce. "To utworzyło dla mnie sesję bezpośrednio z pliku node.js na kod trasy"
Następnie połączyłem się z websemetlem za pomocą PHP, teraz widzę, że sesja nie ma problemu! Udało mi się otworzyć wiele kart w przeglądarce i ta sama sesja jest zgodna z oczekiwaniami.
Powodem, dla którego zadziałało tym razem jest to, że URL https://10.0.4.18:8020/set/MikeA ustanowił sesję i powiązał ją między moją przeglądarką a sesją i stamtąd mogłem odczytać/zapisać swoją sesję z socket.io przy użyciu funkcji express-socket.io- pakiet sesji https://www.npmjs.com/package/express-socket.io-session.
Jeśli jednak nie utworzę sesji przy użyciu adresu URL ręcznie, sesja będzie dobra tylko dla jednego obciążenia strony. Za każdym razem, gdy strona jest ponownie ładowana, sesja jest niszczona, jakby nigdy nie istniała!
Pytanie
muszę rozwijać takie samo zachowanie, gdy połączenie z websocket poprzez https://10.0.4.18:8020/set/MikeA podczas łączenia z socket.io.
Jak mogę ustanowić handshake pomiędzy serwerem PHP a gniazdem socket.io, w którym dwa serwery mogą powiązać dane sesji z właściwym użytkownikiem za każdym razem, gdy strona PHP zostanie ponownie załadowana lub otwarta zostanie nowa karta przeglądarki?
Oto mój kod 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);
});
Oto jak połączyć się z websocket z serwera 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>
nie wiem Myślę, że jest to możliwe, ponieważ po ponownym załadowaniu strony lub po przejściu przeglądarki do innej instancji wszystkie instancje kodu JavaScript umierają, ponieważ są unikalne na stronie i konieczne jest ustanowienie nowego połączenia z gniazdem, jeśli chcesz zidentyfikować użytkownika z nowego połączenie najlepszym sposobem jest praca z sesjami, kiedy użytkownik loguje się lub łączy po raz pierwszy, unikalny identyfikator sesji to c jest ponownie zapisywany i wysyłany z serwera do użytkownika i przechowywany lokalnie, więc za każdym razem, gdy klient rozpoczyna nowe połączenie, identyfikuje to samo z identyfikatorem sesji do serwera, a serwer powinien rozpoznać –
@DanielMendel Jak przekażę sesję z powrotem do Klient? Z serwera node.js, jak załadowałbym konkretny identyfikator sesji po pierwszym żądaniu? –