socket.io e sessão?

95

Estou usando o Express Framework. Quero acessar os dados da sessão de socket.io. Tentei expressar dynamicHelpers com dados de client.listener.server.dynamicViewHelpers, mas não consigo obter dados de sessão. Existe uma maneira simples de fazer isso? Por favor veja o código

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
fonte
5
Ou pode usar este post MUITO BOM: danielbaulig.de/socket-ioexpress
Fabiano Soriani
3
@FabianoPS - não funciona mais - a conexão não fornece mais o método parseCookie do qual ele se baseia.
UpTheCreek
1
@UpTheCreek - Já que o connect não usa mais o método parseCookie, como isso pode ser possível?
Aust
@Aust - Boa pergunta, não sei qual é a melhor abordagem agora. Esta é realmente uma bagunça, IMO. Irritantemente, a maioria das discussões sobre soluções alternativas também estão focadas em socket.io (nem todo mundo está usando socket.io!). Há uma função parseSignedCookie agora, mas ela também é privada, então também corre o risco de interromper as alterações.
UpTheCreek de
2
Para versões mais recentes de Socket.IO (1.x) e Express (4.x), verifique esta pergunta do SO: stackoverflow.com/questions/25532692/…
pootzko

Respostas:

68

Isso não funcionará para sockets passando pelo transporte flashsocket (não envia ao servidor os cookies necessários), mas funciona de forma confiável para todo o resto. Acabei de desabilitar o transporte flashsocket no meu código.

Para fazer funcionar, no lado expresso / conexão, defino explicitamente o armazenamento de sessão para que possa usá-lo dentro do soquete:

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

Em seguida, dentro do meu código de soquete, incluo a estrutura de conexão para que possa usar sua análise de cookies para recuperar o connect.sid dos cookies. Em seguida, procuro a sessão no armazenamento de sessão que tem esse connect.sid assim:

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!!!!
    });
  }
});

Você pode então usar a sessão conforme necessário.

pr0zac
fonte
3
Parece que socket_client.request foi removido nas últimas versões de socket.io-node
Art
6
Cuidado ... há novas convenções para fazer isso agora ... Eu sugeriria usar a autenticação Socket.IO em vez disso. Veja a postagem de @Jeffer
BMiner
2
Infelizmente, isso não vai funcionar mais - parseCookie não faz mais parte dos utilitários de conexão. Aparentemente, nunca fez parte da API pública. Há uma alternativa complicada - parseSignedCookie, mas isso também é privado, então acho que também corre o risco de desaparecer ..
UpTheCreek
Agora que estou pensando sobre isso ... por que não definir a loja para os cookies e a loja para o soquete na mesma loja?
James
34

A solução do módulo Socket.IO-sessions expõe o aplicativo a ataques XSS, expondo a ID da sessão no nível do cliente (script).

Em vez disso, verifique esta solução (para Socket.IO> = v0.7). Veja a documentação aqui .

Jeffer
fonte
1
@Jeffer - essa segunda solução não funcionará mais com a versão atual do Connect.
UpTheCreek de
2
-1 socket.ioé o que está expondo o ID da sessão, não aquele módulo. Isso não é um grande problema, já que o ID da sessão é armazenado do lado do cliente em um cookie de qualquer maneira ... Além disso, esse tutorial não funciona para a versão mais recente do Express.
Aust
1
o link da solução simplesmente redireciona para a socket.iopágina do github ..?
TJ
8

Eu sugiro não reinventar totalmente a roda. As ferramentas de que você precisa já são um pacote npm. Acho que é disso que você precisa: session.socket.io Estou usando hoje em dia e será muito útil, acho !! Vincular a sessão expressa à camada socket.io terá muitas vantagens!

Francesco
fonte
6
Aqui está um módulo atualizado que oferece suporte a socket.io-express-sessions para socket.io> = 1.0 github.com/xpepermint/socket.io-express-session
blnc
4

Edit: Depois de tentar alguns módulos que não funcionaram, eu na verdade escrevi minha própria biblioteca para fazer isso. Plugue sem vergonha: vá dar uma olhada em https://github.com/aviddiviner/Socket.IO-sessions . Vou deixar meu antigo post abaixo para fins históricos:


Eu fiz este trabalho perfeitamente sem ter que contornar o transporte flashsocket conforme a solução do pr0zac acima. Também estou usando o expresso com Socket.IO. Veja como.

Primeiro, passe o ID da sessão para a vista:

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

Em sua visão, vincule-o ao lado do cliente 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'});"/>

Em seguida, no listener Socket.IO do lado do servidor, pegue-o e leia / grave os dados da sessão:

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
    });
  });
});

No meu caso, o meu session_storeé Redis, usando a redis-connectbiblioteca.

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

Espero que isso ajude alguém que encontra esta postagem enquanto pesquisa no Google (como eu fiz;)

Dave
fonte
8
Colocar seu id de sessão no html do cliente não é uma boa ideia do ponto de vista da segurança ...
UpTheCreek
4
Por que colocar o ID da sessão no HTML é uma ideia tão ruim quando o ID da sessão já está armazenado em um cookie local?
Gavin de
3
Porque os cookies não podem ser acessados ​​do javascript quando definidos como cookies HttpOnly. Ao colocar session.sid no HTML, você dá ao invasor tudo o que ele precisa no DOM.
rochal
3

Veja isto: Autenticação Socket.IO

Eu sugeriria não buscar nada via client.request...ou, client.listener...pois isso não está diretamente anexado ao clientobjeto e sempre aponta para o último usuário conectado!

Shripad Krishna
fonte
2

Confira Socket.IO-connect

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

Isso permitirá que você envie a (s) solicitação (ões) Socket.IO para baixo na pilha de middleware Express / Connect antes de manipulá-la com manipuladores de eventos Socket.IO, dando a você acesso à sessão, cookies e muito mais. Embora não tenha certeza de que funcione com todos os transportes do Socket.IO.

BMiner
fonte
infelizmente, esse módulo ainda está usando v0.6 de socket.io
fent
2

Você pode usar express-socket.io-session .

Compartilhe um middleware de sessão expressa baseado em cookie com socket.io. Funciona com express> 4.0.0 e socket.io> 1.0.0 e não é compatível com versões anteriores.

Funcionou para mim !!

nonybrighto
fonte
Ei. Como você usaria os valores da sessão no front-end? Não consigo vê-los nos documentos do NPM.
Hari Ram
1

Você pode dar uma olhada em: https://github.com/bmeck/session-web-sockets

ou, alternativamente, você pode usar:

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

Espero que isto ajude.

intelidiota
fonte
Eu sei session-web-sockets, mas não quero usar uma biblioteca para isso, estou procurando uma solução simples. Tentei client.listener.server.viewHelpers; mas retornou este: {}
sfs
2
embora pareça funcionar a princípio, leva a condições de corrida. Eu sugiro que você evite isso completamente.
Shripad Krishna
1

Não tenho certeza se estou fazendo certo. https://github.com/LearnBoost/socket.io/wiki/Authorizing

Com os dados do handshake, você pode acessar os cookies. E nos cookies, você pode pegar connect.sid, que é o id de sessão de cada cliente. Em seguida, use o connect.sid para obter os dados da sessão do banco de dados (presumo que você esteja usando o RedisStore)

Tan Nguyen
fonte
este é exatamente o caminho a seguir, mas você não é legal, então você não pode obter pontos de estouro de pilha. github.com/tcr/socket.io-session e github.com/functioncallback/session.socket.io Gosto um pouco mais do primeiro, é mais limpo. O segundo é um pouco melhor documentado.
James
@TJ Lamento por isso, mas você percebeu que a resposta foi há 2 anos? E provavelmente não funcionaria agora
Tan Nguyen
@TanNguyen Eu sei, é por isso que eu o notifiquei para que você possa atualizar a resposta necessariamente ao invés de apontar as pessoas para links mortos
TJ
@TJ Obrigado por isso. Infelizmente, mudei de socket.io devido a problemas de desempenho há 2 anos. Portanto, não sei qual é a forma atual de lidar com a sessão em socket.io
Tan Nguyen