socket.io dan sesi?

96

Saya menggunakan kerangka ekspres. Saya ingin mencapai data sesi dari socket.io. Saya mencoba mengekspresikan dynamicHelpers dengan data client.listener.server.dynamicViewHelpers, tetapi saya tidak bisa mendapatkan data sesi. Apakah ada cara sederhana untuk melakukan hal ini? Silakan lihat kodenya

app.listen(3000);

var io = require('socket.io');
var io = io.listen(app);

io.on('connection', function(client){
    // I want to use session data here
    client.on('message', function(message){
        // or here
    });
    client.on('disconnect', function(){
        // or here
    }); 
});
sfs
sumber
5
Atau dapat menggunakan posting SANGAT BAGUS ini: danielbaulig.de/socket-ioexpress
Fabiano Soriani
3
@FabianoPS - tidak akan berfungsi lagi - koneksi tidak lagi menyediakan metode parseCookie yang diandalkannya.
UpTheCreek
1
@UpTheCreek - Karena koneksi tidak lagi menggunakan metode parseCookie, bagaimana mungkin?
Aust
@Aust - Pertanyaan bagus, saya tidak tahu apa pendekatan terbaik sekarang. Ini benar-benar IMO yang berantakan. Sayangnya, sebagian besar diskusi penyelesaian masalah juga difokuskan pada socket.io (tidak semua orang menggunakan socket.io!). Ada fungsi parseSignedCookie sekarang, tapi itu juga pribadi, jadi berisiko merusak perubahan juga.
UpTheCreek
2
Untuk versi Socket.IO (1.x) dan Express (4.x) yang lebih baru, periksa pertanyaan SO ini: stackoverflow.com/questions/25532692/…
pootzko

Jawaban:

68

Ini tidak akan berfungsi untuk soket yang melewati transportasi flashsocket (tidak mengirim server cookie yang diperlukan) tetapi berfungsi dengan andal untuk yang lainnya. Saya hanya menonaktifkan transportasi flashsocket dalam kode saya.

Untuk membuatnya berfungsi, di sisi express / connect, saya secara eksplisit mendefinisikan penyimpanan sesi sehingga saya dapat menggunakannya di dalam soket:

MemoryStore = require('connect/middleware/session/memory'),
var session_store = new MemoryStore();
app.configure(function () {
  app.use(express.session({ store: session_store }));
});

Kemudian di dalam kode soket saya, saya menyertakan kerangka kerja koneksi sehingga saya dapat menggunakan penguraian cookie untuk mengambil connect.sid dari cookie. Saya kemudian mencari sesi di penyimpanan sesi yang memiliki connect.sid itu seperti:

var connect = require('connect');
io.on('connection', function(socket_client) {
  var cookie_string = socket_client.request.headers.cookie;
  var parsed_cookies = connect.utils.parseCookie(cookie_string);
  var connect_sid = parsed_cookies['connect.sid'];
  if (connect_sid) {
    session_store.get(connect_sid, function (error, session) {
      //HOORAY NOW YOU'VE GOT THE SESSION OBJECT!!!!
    });
  }
});

Anda kemudian dapat menggunakan sesi sesuai kebutuhan.

pr0zac.dll
sumber
3
Sepertinya socket_client.request telah dihapus di versi terbaru socket.io-node
Art
6
Hati-hati ... ada konvensi baru untuk melakukan ini sekarang ... Saya sarankan menggunakan otentikasi Socket.IO sebagai gantinya. Lihat postingan dari @Jeffer
BMiner
2
Sayangnya ini tidak akan berfungsi lagi - parseCookie bukan lagi bagian dari utilitas koneksi. Rupanya itu tidak pernah menjadi bagian dari api publik. Ada alternatif yang berantakan - parseSignedCookie, tetapi ini juga pribadi, jadi saya rasa ini berisiko menghilang juga ..
UpTheCreek
Sekarang setelah saya memikirkan hal ini .... mengapa tidak mengatur toko untuk cookie dan toko untuk soket ke toko yang sama?
James
34

Solusi modul Socket.IO-session memaparkan aplikasi ke serangan XSS dengan mengekspos ID sesi di level klien (scripting).

Periksa solusi ini sebagai gantinya (untuk Socket.IO> = v0.7). Lihat dokumen di sini .

Jeffer
sumber
1
@Jeffer - solusi kedua itu tidak akan berfungsi lagi dengan versi koneksi saat ini.
UpTheCreek
2
-1 socket.ioadalah yang mengekspos ID sesi, bukan modul itu. Ini bukan masalah besar karena ID sesi disimpan di sisi klien dalam cookie ... Juga tutorial itu tidak berfungsi untuk versi Express terbaru.
Aust
1
link solusi Anda hanya mengarahkan ke socket.iohalaman github ..?
TJ
8

Saya menyarankan untuk tidak sepenuhnya menemukan kembali roda. Alat yang Anda butuhkan sudah merupakan paket npm. Saya pikir inilah yang Anda butuhkan: session.socket.io Saya menggunakannya di hari-hari ini dan itu akan sangat membantu saya kira !! Menghubungkan sesi ekspres ke lapisan socket.io akan memiliki banyak keuntungan!

Francesco
sumber
6
Berikut adalah modul yang diperbarui yang mendukung sesi socket.io-express untuk socket.io> = 1.0 github.com/xpepermint/socket.io-express-session
blnc
4

Sunting: Setelah mencoba beberapa modul yang tidak berfungsi, saya benar-benar pergi dan menulis perpustakaan saya sendiri untuk melakukan ini. Steker yang tidak tahu malu: periksa di https://github.com/aviddiviner/Socket.IO-sessions . Saya akan meninggalkan posting lama saya di bawah ini untuk tujuan sejarah:


Saya mendapat pekerjaan ini cukup rapi tanpa harus bypass flashsocket transportasi sesuai pr0zac 's solusi di atas. Saya juga menggunakan express dengan Socket.IO. Begini caranya.

Pertama, teruskan ID sesi ke tampilan:

app.get('/', function(req,res){
  res.render('index.ejs', {
    locals: { 
      connect_sid: req.sessionID
      // ...
    }
  });
});

Kemudian dalam tampilan Anda, tautkan dengan sisi klien Socket.IO:

<script>
  var sid = '<%= connect_sid %>';
  var socket = new io.Socket();
  socket.connect();
</script>
<input type="button" value="Ping" onclick="socket.send({sid:sid, msg:'ping'});"/>

Kemudian di pendengar Socket.IO sisi server Anda, ambil dan baca / tulis data sesi:

var socket = io.listen(app);
socket.on('connection', function(client){
  client.on('message', function(message){
    session_store.get(message.sid, function(error, session){
      session.pings = session.pings + 1 || 1;
      client.send("You have made " + session.pings + " pings.");
      session_store.set(message.sid, session);  // Save the session
    });
  });
});

Dalam kasus saya, saya session_storeadalah Redis, menggunakan redis-connectperpustakaan.

var RedisStore = require('connect-redis');
var session_store = new RedisStore;
// ...
app.use(express.session({ store: session_store }));

Semoga ini membantu seseorang yang menemukan posting ini saat mencari Google (seperti yang saya lakukan;)

Dave
sumber
8
Menempatkan id sesi Anda di html klien bukanlah ide yang baik dari perspektif keamanan ...
UpTheCreek
4
Mengapa menempatkan ID sesi di HTML merupakan ide yang buruk ketika ID sesi sudah disimpan di cookie lokal?
Gavin
3
Karena cookie tidak dapat diakses dari javascript jika disetel sebagai cookie HttpOnly. Dengan meletakkan session.sid di HTML Anda memberi penyerang semua yang mereka butuhkan di DOM.
rochal
3

Lihat ini: Otentikasi Socket.IO

Saya menyarankan untuk tidak mengambil apa pun melalui client.request...atau client.listener...karena itu tidak langsung melekat pada clientobjek dan selalu mengarah ke pengguna yang terakhir masuk!

Shripad Krishna
sumber
2

Lihat Socket.IO-connect

Hubungkan WebSocket Middleware Wrapper Around Socket.IO-node https://github.com/bnoguchi/Socket.IO-connect

Ini akan memungkinkan Anda untuk mendorong permintaan Socket.IO ke tumpukan middleware Express / Connect sebelum menanganinya dengan event handler Socket.IO, memberi Anda akses ke sesi, cookie, dan banyak lagi. Meskipun, saya tidak yakin itu bekerja dengan semua transport Socket.IO.

BMiner
sumber
sayangnya modul itu masih menggunakan v0.6 dari socket.io
fent
2

Anda dapat menggunakan express-socket.io-session .

Bagikan middleware sesi ekspres berbasis cookie dengan socket.io. Bekerja dengan express> 4.0.0 dan socket.io> 1.0.0 dan tidak akan kompatibel ke belakang.

Bekerja untuk saya !!

nonybrighto
sumber
Hei. Bagaimana Anda akan menggunakan nilai sesi di front-end? Saya tidak bisa melihatnya di npm docs.
Hari Ram
1

Anda dapat melihat ini: https://github.com/bmeck/session-web-sockets

atau sebagai alternatif, Anda dapat menggunakan:

io.on('connection', function(client) { 
  var session = client.listener.server.viewHelpers; 
  // use session here 
});

Semoga ini membantu.

intellidiot
sumber
Saya tahu sesi-web-soket tetapi saya tidak ingin menggunakan perpustakaan untuk ini, saya mencari solusi sederhana. Saya mencoba client.listener.server.viewHelpers; tetapi mengembalikan ini: {}
sfs
2
meskipun ini tampaknya berhasil pada awalnya, ini mengarah pada kondisi balapan. Saya sarankan Anda menghindarinya sepenuhnya.
Shripad Krishna
1

Saya tidak yakin apakah saya melakukannya dengan benar. https://github.com/LearnBoost/socket.io/wiki/Authorizing

Dengan data jabat tangan, Anda dapat mengakses cookie. Dan di cookie, Anda dapat mengambil connect.sid yang merupakan id sesi untuk setiap klien. Dan kemudian gunakan connect.sid untuk mendapatkan data sesi dari database (Saya berasumsi Anda menggunakan RedisStore)

Tan Nguyen
sumber
ini persis cara untuk pergi tetapi Anda tidak keren sehingga Anda tidak bisa mendapatkan poin stack overflow. github.com/tcr/socket.io-session dan github.com/functioncallback/session.socket.io Saya suka yang pertama, sedikit lebih baik, lebih bersih. Yang kedua didokumentasikan dengan lebih baik.
Yakobus
@TJ Saya minta maaf tentang itu tetapi apakah Anda menyadari bahwa jawabannya adalah 2 tahun yang lalu? Dan itu mungkin tidak akan berhasil sekarang
Tan Nguyen
@TanNguyen Saya tahu, itulah mengapa saya memberi tahu Anda sehingga Anda dapat memperbarui jawaban dengan tepat daripada mengarahkan orang ke tautan mati
TJ
@TJ Terima kasih untuk itu. Sayangnya, saya pindah dari socket.io karena masalah kinerja 2 tahun lalu. Oleh karena itu, saya tidak tahu apa cara menangani sesi saat ini di socket.io
Tan Nguyen