2015-09-22 9 views
9

मैं एक WebSocket पोर्ट 8020 पर सर्वर 10.0.4.18 पर Node.js 4.0 पर चल रहा socket.io v1.3 का उपयोग कर मेरी WebSocket लागू किया है, व्यक्त करते हैं, और एक्सप्रेस-सत्र।कैसे पीएचपी वेब सर्वर और Socket.io Node.js सर्वर पर जो हाथ मिलाना बनाने के लिए?

प्रोजेक्ट परिभाषा

मैं हर उपयोगकर्ता एक PHP आवेदन से यह करने के लिए जोड़ता है के लिए socket.io में एक सत्र बनाने में सक्षम होने की जरूरत है। उपयोगकर्ता के पहले HTTP अनुरोध को भेजने के बाद, मैं उन्हें एक टोकन का उपयोग करके प्रमाणित कर दूंगा जो HTTP अनुरोध के साथ PHP से socket.io तक पारित किया जाएगा।

के बाद उपयोगकर्ता को प्रमाणीकृत किया है, मैं socket.io सत्र के अंदर कुछ व्यक्तिगत डेटा को बचाने के लिए बाद में पुन: उपयोग करने की जरूरत है। हर बार उपयोगकर्ता PHP अनुप्रयोग को रीफ्रेश करते हैं, socket.io को पहले से बनाए गए सत्र डेटा को जानने की आवश्यकता होगी।

समस्या

हर बार जब उपयोगकर्ता पुनः लोड/ताजा कर पीएचपी पेज "जहां वह/वह से जुड़े", सत्र डेटा खो जाते हैं। सर्वर यह जानने में विफल रहता है कि कनेक्शन XYZ सत्र से संबंधित है जिसे पहले बनाया गया था।

मुझे यकीन है कि जहां दो सर्वर socket.io सत्र के लिए टाई के लिए एक अनूठा डेटा विनिमय कर सकते हैं PHP और Node.js के बीच एक हाथ मिलाना बनाने का तरीका नहीं हूँ।

समस्या

पर बहुत करीब से देखें मैं अपने ब्राउज़र में इस लिंक https://10.0.4.18:8020/set/MikeA खोला।

तब मैं WebSocket से जुड़ा PHP का उपयोग "यह एक सत्र मेरे लिए सीधे मार्ग कोड प्रति Node.js से बनाए गए", अब मैं देख सकता हूँ कि कोई समस्या नहीं के साथ सत्र लाठी! मैं ब्राउज़र में कई टैब खोलने में सक्षम था और वही सत्र अपेक्षित था।

इस बार काम करने का कारण यह है कि यूआरएल https://10.0.4.18:8020/set/MikeA ने एक सत्र स्थापित किया और इसे अपने ब्राउज़र और सत्र के बीच बांध दिया और वहां से मैं socket.io से अपना सत्र पढ़ने/लिखने में सक्षम था- एक्सप्रेस-सॉकेट.ओ- सत्र पैकेज https://www.npmjs.com/package/express-socket.io-session

लेकिन अगर मैं यूआरएल का उपयोग कर मैन्युअल रूप से केवल सत्र केवल एक पृष्ठ लोड के लिए अच्छा होगा सत्र बनाने नहीं है। और हर बार पृष्ठ को फिर से लोड किया जाता है, सत्र नष्ट हो जाता है जैसे कि यह कभी अस्तित्व में नहीं था!

प्रश्न

मैं जब https://10.0.4.18:8020/set/MikeA के माध्यम से WebSocket के लिए कनेक्शन 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); 
}); 

है यहाँ कैसे मैं 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> 
+0

मुझे नहीं पता ऐसा लगता है कि जब पृष्ठ को फिर से लोड किया जाता है या ब्राउज़र अलग-अलग होते हैं तो सभी जावास्क्रिप्ट उदाहरण मर जाते हैं क्योंकि वे प्रति पृष्ठ अद्वितीय होते हैं और एक नया सॉकेट कनेक्शन स्थापित करने की आवश्यकता होती है, यदि आप नए से उपयोगकर्ता की पहचान करना चाहते हैं कनेक्शन सत्र के साथ काम करने का सबसे अच्छा तरीका है, जब उपयोगकर्ता पहली बार लॉग इन करता है या कनेक्ट करता है, तो एक अद्वितीय सत्र आईडी सी है सर्वर से सर्वर पर भेजा और भेजा गया और स्थानीय रूप से संग्रहीत किया गया, इसलिए जब भी क्लाइंट एक नया कनेक्शन शुरू करता है, तो यह सर्वर पर सत्र आईडी के साथ स्वयं को पहचानता है और सर्वर को –

+0

@DanielMendel को दोबारा जोड़ना चाहिए, मैं सत्र को वापस कैसे पास करूंगा ग्राहक? Node.js सर्वर से, मैं पहले अनुरोध के बाद एक विशिष्ट sessionID कैसे लोड करूंगा? –

उत्तर

2

स्टोर ब्राउज़र में टोकन से WebSocket से कनेक्ट और यह php से हर अनुरोध के साथ भेज रहा है , एक प्राधिकरण भालू जैसा दिखता है:

Authorization: Bearer token 

तो हर बार node.js सर्वर मिलता है एक अनुरोध है कि आप टोकन की तुलना कर सकते हैं जिस पर उपयोगकर्ता मेल खाता है और डेटा प्राप्त करता है।

आप किसी तालिका में समाप्ति तिथि के साथ उपयोगकर्ता आईडी और टोकन के बीच संबंधों को स्टोर कर सकते हैं और प्रत्येक लॉगिन पर टोकन रीफ्रेश कर सकते हैं।

इसके अलावा, अगर आप एक तालिका का उपयोग करने के जेडब्ल्यूटी

के साथ, आप, टोकन में डेटा स्टोर कर सकते हैं

आप यहाँ और अधिक जानकारी प्राप्त कर सकते नहीं करना चाहती:

http://jwt.io/

+0

मैं एलेक्स 7 से पूरी तरह से सहमत हूं, वास्तव में पहले मैं socket.io नोड के साथ php सत्र में शामिल हो गया था, और यह मेरे लिए अच्छा काम कर रहा है, लेकिन मेरे पास सर्वर में भौतिक PHP सत्र से जुड़ा हुआ बहुत सी युग्मित कोड था .. और यह है एक स्केलेबिलिटी समस्या है, एक अन्य कारण यह है कि यदि आप जेसन प्रारूप के लिए अनिश्चित बैकएंड प्रतिक्रियाएं लिख सकते हैं, तो आप प्रत्येक अनुरोध में प्रतिक्रिया दृश्य भेजने के लिए सर्वर का उपयोग कर क्लाइंट प्रदर्शन का उपयोग करके दृश्य प्रस्तुत कर सकते हैं ... और यह बेहतर होगा प्रदर्शन और आप इसे ऐप में अधिक तेज़ी से पैकेज कर सकते हैं (जैसे आयनिक, फोनगैप, प्रतिक्रिया आदि ..) –

+0

@ Alex7 आपकी प्रतिक्रिया के लिए धन्यवाद। अगर मैं आपको सही ढंग से समझता हूं, तो मेरे पास मेरे node.js पर एक रिलेशनशिप ऑब्जेक्ट होना चाहिए जो सत्र आईडी और शीर्षलेख में पारित टोकन के बीच संबंध रखता है। फिर मिडलवेयर में मैं एक चेक जोड़ता हूं, यदि टोकन पहले से मौजूद है तो मौजूदा सत्र लोड करें। यदि नहीं, तो एक नया सत्र उत्पन्न करें और इसे संबंध वस्तु में संग्रहीत करें। लेकिन, मैं एक नया सत्र आईडी उत्पन्न करने के लिए एक्सप्रेस-सत्र को कैसे बल दूंगा? –

+0

@ माइकिया मुझे लगता है कि आप सत्र.regenerate() की तलाश में हैं जो आप यहां पा सकते हैं https://github.com/expressjs/session#sessionregenerate। लेकिन यहां 2 परिदृश्य हैं: सबसे पहले, आप 1 घंटे के बाद कुंजी की समाप्ति करते हैं और आपको बार-बार उपयोगकर्ता लॉगिन को न रखने के लिए पुनर्जन्म की आवश्यकता होती है, दूसरा, जब आप दोबारा लॉगिन करना चाहते हैं तो दूसरा सत्र समाप्त हो जाता है और आप नहीं करते हैं पुनर्जन्म की आवश्यकता है, आप बस एक नया सत्र बनाते हैं। जब आप ऐप को अपग्रेड करते हैं तो आप एक तंत्र बना सकते हैं, आप उस ऑब्जेक्ट को हटाते हैं जो sessionID और टोकन संग्रहीत करता है और सभी उपयोगकर्ताओं को फिर से लॉगिन करना होगा ताकि आपके पास पुराना डेटा न हो। – Alex7

संबंधित मुद्दे