55 votes

node.JS comment créer et lire une session avec express

Je fais une application de chat avec socket.io et express.

Voici donc ce que je veux faire. Lorsque les utilisateurs entrent dans l'application de chat, le client envoie l'email de l'utilisateur au serveur nodejs, je veux créer une session avec la valeur de l'email de l'utilisateur.

Lorsque les utilisateurs envoient un message de chat au serveur nodejs, si les données envoyées par le client contiennent le même email que la session créée, alors le message sera diffusé, sinon non.

Voici donc mon code, je vais devoir le faire fonctionner comme prévu. Ce que je doute de mon code est, je ne sais pas si une session a été créée, et comment vérifier cette session.

var io   = require('socket.io'),
    express = require('express');
    querystring = require('querystring');

var app = express.createServer();
app.get('/', function(req, res){
    var sessionVal = querystring.parse(req.url.substr(2));// sessionVal is an email for example: me@gmail.com
    app.use(express.cookieParser());
    app.use(express.session({ secret: sessionVal }));
});
var socket = io.listen(app);
socket.on('connection', function(client) {
    client.on('message', function(message) {
        // message will be an object {text:'user text chat blah blah', email:'me@gmail.com'}
        // if the seesion stored, has the same value with message.email
        // then the message will be broadcasted
            socket.broadcast(message.text);
        // else will not broadcast  
    });
});

app.listen(4000);

82voto

Shtééf Points 10444

Je dois signaler ici que vous n'ajoutez pas correctement un intergiciel à l'application. Le site app.use ne doivent pas être effectués dans le cadre de la app.get mais en dehors de celui-ci. Il suffit de les appeler directement après createServer ou consultez le site les autres exemples dans la documentation .

Le secret que vous passez à express.session devrait être une constante de type chaîne de caractères, ou peut-être quelque chose pris dans un fichier de configuration. Ne lui donnez pas quelque chose que le client pourrait connaître, c'est en fait dangereux. C'est un secret que seul le serveur doit connaître.

Si vous voulez stocker l'adresse électronique dans la session, il suffit de faire quelque chose du genre :

req.session.email = req.param('email');

Ceci étant dit...


Si je comprends bien, ce que vous essayez de faire, c'est de traiter une ou plusieurs requêtes HTTP et de garder la trace d'une session, puis plus tard d'ouvrir une connexion Socket.IO à partir de laquelle vous avez également besoin des données de session.

Ce qui est délicat dans ce problème, c'est que le moyen utilisé par Socket.IO pour faire fonctionner la magie sur n'importe quel ordinateur http.Server c'est en détournant le request événement. Ainsi, les "Express" (ou plutôt Connectez-vous à ) n'est jamais appelé sur la connexion Socket.IO.

Je pense que vous pouvez faire en sorte que cela fonctionne, cependant, avec un peu d'astuce.

Vous pouvez accéder aux données de session de Connect ; il vous suffit d'obtenir une référence au magasin de session. La façon la plus simple de le faire est de créer le magasin vous-même avant d'appeler la commande express.session :

// A MemoryStore is the default, but you probably want something
// more robust for production use.
var store = new express.session.MemoryStore;
app.use(express.session({ secret: 'whatever', store: store }));

Chaque magasin de session possède un get(sid, callback) méthode. Le site sid ou l'ID de la session, est stocké dans un cookie sur le client. Le nom par défaut de ce cookie est connect.sid . (Mais vous pouvez lui donner n'importe quel nom en spécifiant un nom de type key dans votre express.session appel.)

Ensuite, vous devez accéder à ce cookie sur la connexion Socket.IO. Malheureusement, Socket.IO ne semble pas vous donner l'accès au cookie. http.ServerRequest . Une solution de contournement simple consisterait à récupérer le cookie dans le navigateur et à l'envoyer via la connexion Socket.IO.

Le code sur le serveur ressemblerait alors à ce qui suit :

var io      = require('socket.io'),
    express = require('express');

var app    = express.createServer(),
    socket = io.listen(app),
    store  = new express.session.MemoryStore;
app.use(express.cookieParser());
app.use(express.session({ secret: 'something', store: store }));

app.get('/', function(req, res) {
  var old = req.session.email;
  req.session.email = req.param('email');

  res.header('Content-Type', 'text/plain');
  res.send("Email was '" + old + "', now is '" + req.session.email + "'.");
});

socket.on('connection', function(client) {
  // We declare that the first message contains the SID.
  // This is where we handle the first message.
  client.once('message', function(sid) {
    store.get(sid, function(err, session) {
      if (err || !session) {
        // Do some error handling, bail.
        return;
      }

      // Any messages following are your chat messages.
      client.on('message', function(message) {
        if (message.email === session.email) {
          socket.broadcast(message.text);
        }
      });
    });
  });
});

app.listen(4000);

Cela suppose que vous souhaitez uniquement lire une session existante. Vous ne pouvez pas réellement créer ou supprimer des sessions, car les connexions Socket.IO peuvent ne pas avoir de réponse HTTP à envoyer à l'utilisateur. Set-Cookie dans l'en-tête (pensez aux WebSockets).

Si vous voulez modifier les sessions, cela peut fonctionner avec certains magasins de session. Un CookieStore ne fonctionnerait pas, par exemple, parce qu'il doit également envoyer un message de type Set-Cookie ce qui n'est pas le cas. Mais pour les autres magasins, vous pouvez essayer d'appeler la fonction set(sid, data, callback) et voyez ce qui se passe.

0 votes

Merci pour toutes les explications détaillées. J'utilise req.session.email = req.param('email') ; Comment puis-je accéder à la valeur email stockée ?

0 votes

J'ai oublié de signaler un bug lorsque j'utilise req.session.email = req.param('email'), l'erreur du serveur dit cannot sett property email of undefined.

0 votes

Je crois toujours que vous utilisez mal le middleware. Quand c'est fait correctement, vous devriez avoir un req.session . Comme je l'ai montré dans l'exemple, vous pouvez accéder à l'email stocké en utilisant req.session.email .

5voto

Donald Lian Points 61

J'ai oublié de signaler un bug lorsque j'utilise req.session.email = req.param('email'), l'erreur du serveur dit cannot sett property email of undefined.

La raison de cette erreur est un mauvais ordre de app.use. Vous devez configurer express dans cet ordre :

app.use(express.cookieParser());
app.use(express.session({ secret: sessionVal }));
app.use(app.route);

5voto

nponeccop Points 8111

Il est difficile de faire interagir le support de socket.io et des sessions connect. Le problème n'est pas que socket.io "détourne" la demande d'une manière ou d'une autre, mais que certains transports socket.io (je pense à flashsockets) ne prennent pas en charge les cookies. Je peux me tromper sur les cookies, mais mon approche est la suivante :

  1. Implémenter un magasin de session séparé pour socket.io qui stocke les données dans le même format que connect-redis.
  2. Faites en sorte que le cookie de session de connexion ne soit pas http-only afin qu'il soit accessible depuis le JS du client.
  3. Lors d'une connexion socket.io, envoyer le cookie de session via socket.io du navigateur au serveur.
  4. Stocke l'identifiant de session dans une connexion socket.io, et l'utilise pour accéder aux données de session de redis.

2voto

CommaToast Points 1165

Les étapes que j'ai franchies :

  1. Incluez le fichier angular-cookies.js dans le HTML !

  2. Initez les cookies comme n'étant PAS http-only dans les applications côté serveur :

    var cookieSettings = {path : '/', httpOnly : false, maxAge : null} ; app.configure(function(){ //un tas de trucs app.use(express.cookieSession({secret : 'mySecret', store : store, cookie : cookieSettings})) ;

  3. Ensuite, dans le fichier services.jss côté client, je mets ['ngCookies'] comme ceci :

    angular.module('swrp', ['ngCookies']).//etc

  4. Ensuite, dans controller.js, dans ma fonction UserLoginCtrl, j'ai $cookies avec $scope en haut comme ça :

    function UserLoginCtrl($scope, $cookies, socket) {

  5. Enfin, pour obtenir la valeur d'un cookie à l'intérieur de la fonction contrôleur, j'ai fait :

    var mySession = $cookies['connect.sess'] ;

Maintenant tu peux renvoyer ça au serveur depuis le client. Génial. J'aurais aimé qu'ils mettent ça dans la documentation d'Angular.js. Je l'ai compris en lisant directement le code de angular-cookies.js.

0voto

Varun Sharma Points 75

Bonjour, j'essaye d'ajouter de nouvelles valeurs de session dans node js comme

req.session.portal = false
Passport.authenticate('facebook', (req, res, next) => {
    next()
})(req, res, next)

Pour les stratégies de passeport, je n'obtiens pas la valeur du portail dans la requête Mozilla, mais cela fonctionne bien avec Chrome et Opera.

FacebookStrategy: new PassportFacebook.Strategy({
    clientID: Configuration.SocialChannel.Facebook.AppId,
    clientSecret: Configuration.SocialChannel.Facebook.AppSecret,
    callbackURL: Configuration.SocialChannel.Facebook.CallbackURL,
    profileFields: Configuration.SocialChannel.Facebook.Fields,
    scope: Configuration.SocialChannel.Facebook.Scope,
    passReqToCallback: true
}, (req, accessToken, refreshToken, profile, done) => {
    console.log(JSON.stringify(req.session));

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X