Nodejs Express3 using sessions to check if user is logged in

11,432

Solution 1

Maybe I'm understanding your question wrong, but the only thing you are missing is a route, where you authenticate the user, e.g.:

app.post('/login', function(req, res){
  if(req.body.user == 'Ryan' && req.body.password == 'Dahl'){
    req.session.user = aUserIdOrUserObject;
    res.send(200) // or redirect
  }
};          

This is hust pseudo code. You obviously want to check if user and password match against your database.

The second point you are missing is a permanent session store like https://github.com/masylum/connect-mongodb or https://github.com/CarnegieLearning/connect-mysql-session. The memory store is only usefull for development, in production this could kill your server.

Solution 2

What I do in the app I work, and in order to not have to do this validation in every controller action, is:

//userValidation.js
module.exports = function(req, res, next){
    if(req.body.user == 'Ryan' && req.body.password == 'Dahl'){
        next();
    }else res.send("Not auth");
}

//controller.js
var validate = require("./userValidation");

app.post("/route", validate, function(req, res){
    //if execution get to this point you are sure that user is authenticated.
});

This code is also from the App I work, this is how we set the session to work. For dev purposes you can replace MongoStore with a MemoryStore.

app.configure(function(){
        app.set('views', __dirname + '/views');
        app.set('view engine', 'jade');

        app.use(connect.compress());
        app.use(express.static(__dirname + "/public", { maxAge: 6000000 }));
        app.use(express.favicon(__dirname + "/public/img/favicon.ico", { maxAge: 6000000 }));    
        app.use(express.bodyParser());
        app.use(express.methodOverride());
        app.use(express.cookieParser());
        app.use(express.session({
            secret: config.sessionSecret,
            maxAge: new Date(Date.now() + (1000 * 60 * 15)),
            store: new MongoStore({ url: config.database.connectionString })
        }));
        app.use(function(req, res, next){
            console.log("\n~~~~~~~~~~~~~~~~~~~~~~~{   REQUEST   }~~~~~~~~~~~~~~~~~~~~~~~".cyan);
            res.locals.config = config;
            res.locals.session = req.session;
            res.locals.utils = viewUtils;
            next();
        });
        app.use(app.router);
        app.use(function(req, res, next){
            res.status(404).send("Resource not found");
        });
});

In order to set the user in the session we have this:

var User = require("../utils/modelRegistrar").user; //any way to get the User model
var userRepository = require("../domain/repositories/usuarioRepository");
var hash = require("../utils/hash");

module.exports.init = function(app, io){
    app.publicPost("/login", login);
    app.put("/exit", exit);
};

function login(req, res){
    var dadosDeLogin = req.body.dadosDeLogin; 
    userRepository.autenticar(dadosDeLogin.login, /*hash.md5(*/dadosDeLogin.senha/*)*/, function(err, user){
        if(err) req.next(err);
        if(user){
            user.lastAcess = new Date();
            user.access++;

            userRepository.update(user, ["lastAcess", "acess"], function(err){
                if(err) req.next(err);
                else{
                    req.session.logedUser = user;
                    res.redirect("/home");
                }
            });
        }
        else res.redirect("/#user-not-found");
    });
};

function exit(req, res){
    if(req.session.logedUser) delete req.session.logedUser;
    res.redirect("/");
}

May some part of the code is still in portuguese

Share:
11,432
germainelol
Author by

germainelol

Updated on June 04, 2022

Comments

  • germainelol
    germainelol almost 2 years

    I have the following app.js code

    app.configure(function(){
      app.set('port', process.env.PORT || 3000);
      app.set('views', __dirname + '/views');
      app.enable('jsonp callback');
      app.set('view engine', 'jade');
      app.set('view options', {layout : false});
      app.use(express.bodyParser());
      app.use(express.methodOverride());
      app.use(express.cookieParser());
      app.use(express.session({
        secret : 'abcdefg'      
      }));
      app.use(app.router);
      app.use(express.static(__dirname + '/public'));
      app.use(function(req, res, next){
        res.locals.user = req.session.user;
        next();
      })
    
    });
    

    I'm trying to make it so that the following code on my .jade view will work

    - if(session.user)
              div#logoutsection.pull-right
                a#logout-btn.btn.btn-info.pull-right.top-bar-form-button(href='logout/') Logout
                p#loginprompt.pull-right.login-prompt #{session.user.username} logged In
            - else
              ul.pull-right
                li
              a#signup-btn.btn.pull-right.top-bar-form-button(href='#signup-modal', data-toggle="modal") Sign Up
    

    So if they are not signed in, provide the option to sign up, and if they are signed in, tell them they are 'logged in'. I added in the function at the end of the app.configure code as before it was using dynamicHelpers() I was told that cookieParser() was the way to go, but how would I code this in so that I could check whether my user was logged in and provide their username as I am trying to above?

    Any help appreciated.

    Thanks!

    EDIT: index.js

    'use strict'
    
    var util = require('util');
    var Logger = require('devnull');
    var logger = new Logger({namespacing : 0});
    var User  = require('../schemas/User');
    var Post = require('../schemas/Post');
    
    /**
      * Get Meta information about all the Post's
      */
    var getAllMeta = function(req, res, next){
      Post.getAllMeta(function(err, postsList){
        if(!err && postsList){
          req.postsList = postsList;
        }
        next(err);
      });
    };
    
    /**
      * validate the signup credentials entered by the user
      * @param {String} username 
      * @param {String} pass1 : first password
      * @param {String} pass2 : verification password
      */
    var validateUserData = function(username, pass1, pass2){
      if(pass1.trim() !== pass2.trim()){
        util.log('Passwords not Matching ' + pass1 + ' ' + pass2);
        return 'Passwords not Matching';
      }
      return '';
      //put any other validations here
    };
    
    /*
     * GET home page.
     */
    module.exports = function(app){
      /**
        * Map the URL '/' to the callback
        */
      app.get('/', function(req, res){
        logger.log('Serving request for url [GET]' + req.route.path)
        Post.getAll(function(err, allPosts){
          if(!err && allPosts){
            res.render('index', {'allPosts' : allPosts});
          }else{
            util.log('Error fetching posts from database : ' + err);
            res.render('error');
          }
        });
      });
    
      /**
        * Map the URL '/login' to the callback
        */
      app.post('/login', function(req, res){
        logger.log('Serving request for url [POST] ' + req.route.path);
        var username = req.body.User;
        var password = req.body.Password;
    
        User.validateUser(username, password, function(err, user){
          if(err && !user){
            res.json({
              retStatus : 'failure'  
            });
          }else{
            console.log(user);
            req.session.user = user;
            res.json({
              retStatus : 'success',
              user : user ,
            });
          }
        });
      });
    
      /**
        * Logout the current user and clear the session
        */
      app.get('/logout', function(req, res){
        logger.log('Serving request for url [GET] ' + req.route.path);
        req.session.user = undefined;
        res.redirect('/');
      });
    
      /**
        * Add a new User to database
        */
      app.post('/signup', function(req, res){
        util.log('Serving request for url [POST] ' + req.route.path);
        var signupForm = req.body.signupForm;
        var username = signupForm.username;
        var pass1 = signupForm.pass1;
        var pass2 = signupForm.pass2;
    
        var validateMsg = validateUserData(username, pass1, pass2);
        if(validateMsg !== ''){
          res.json({
            'retStatus' : 'failure',
            'message' : validateMsg
          });
        }else{
          var newUser = new User();
          newUser.username = username;
          newUser.password = pass1;
    
          newUser.save(function(err, savedUser){
            var message = '';
            var retStatus = '';
            if(!err){
              util.log('Successfully created new user with Username : ' + username);
              message = 'Successfully created new user : ' + username;
              retStatus = 'success';
              req.session.user = savedUser;
            }else{
              util.log('Error while creating user : ' + username + ' error : ' + util.inspect(err));
              if(err.code === 11000){
                message = "User already exists";
              }
              retStatus = 'failure';
            }
            res.json({
              'retStatus' : retStatus,
              'message' : message
            });
          });
        }
      });
    
      app.get('/admin', getAllMeta, function(req, res){
        util.log('Serving request for url [GET] ' + req.route.path);    
        if(req.session.user){
          res.render('post', {'postsList' : req.postsList});
        }else{
          res.redirect('/');
        }
      });
    
      /**
        * Save the post to database
        */
      app.post('/admin/save/post', function(req, res){
        var postContent = req.body.postContent;
    
        if(postContent.postKey === '' || postContent.postKey === undefined){
          var post = new Post();
          post.subject  = postContent.postSubject;
          post.content  = postContent.postContent;
          post.author   = req.session.user.username;
          post.tags     = postContent.postTags;
    
          post.save(function(err, response){
            if(!err && response){
              util.log('Successfully saved Post with id : ' + response.id);
              res.json({
                'retStatus' : 'success',
                'data' : response
              })
            }else{
              util.log('Error saving the Post : ' + err);
              res.json({
              'retStatus' : 'failure',
                'error' : err
              });
            }
          });
        }else{
          var conditions = {'key' : postContent.postKey};
          var update = {
            'subject' : postContent.postSubject,
            'content' : postContent.postContent,
            'tags' : postContent.postTags
          };
    
          Post.update(conditions, update, null, function(err, numAffected){
            if(!err && numAffected){
              util.log('Successfully updated the Post with id : ' + postContent.postKey);
              res.json({
                'retStatus' : 'success',
                'numAffected' : numAffected
              });
            }else{
              util.log('Error updating the Post with id : ' + postContent.postKey + ' ' + err);
              res.json({
                'retStatus' : 'failure'
              });
            }
          });
        }
      });
    
      app.get('/post/show/:key', function(req, res){
        Post.findByKey(req.params.key, function(err, postData){
          if(!err && postData){
          postData = postData[0];
            res.json({
              'retStatus' : 'success',
              'postData' : postData
            });
          }else{
            util.log('Error in fetching Post by key : ' + req.params.key);
            res.json({
              'retStatuts' : 'failure',
              'msg' : 'Error in fetching Post by key ' + req.params.key
            });
          }
        }); 
      });
    
      app.post('/admin/save/', function(req, res){
        //container for saving a post
      });
    
      app.get('/admin/remove/:key', function(req, res){
        //container for deleting a post
      });
    
      app.get('/contact', function(req, res){
        util.log('Serving request for url[GET] ' + req.route.path);
        res.render('contact');
      });
    };
    

    User.js

    'use strict'
    
    var util    = require('util');
    var bcrypt  = require('bcrypt');
    var mongoose = require('mongoose');
    var Schema   = mongoose.Schema;
    
    var validatePresenceOf = function(value){
      return value && value.length; 
    };
    
    var toLower = function(string){
      return string.toLowerCase();
    };
    
    var User = new Schema({
      'username' : { type : String, 
                  validate : [validatePresenceOf, 'a Username is required'],
                  set : toLower,
                  index : { unique : true }
                  },
      'password' : String,
    });
    
    User.statics.findUser = function(username, password, cb){
      return  this.find({'username' : username}, cb);
    };
    
    User.statics.validateUser = function(username, password, cb){
      this.find({'username' : username}, function(err, response){
        var user = response[0];
        if(!user || response.length === 0){
          cb(new Error('AuthFailed : Username does not exist'));
        }else{
          if(password == user.password){
            util.log('Authenticated User ' + username);
            cb(null, user);
          }else{
            cb(new Error('AuthFailed : Invalid Password'));
          }
        }
      });
    };
    
    module.exports = mongoose.model('User' , User);
    
    • loganfsmyth
      loganfsmyth over 11 years
      You are setting user as the template variable, but trying to access it as session.user. Maybe try just if(user)?
    • germainelol
      germainelol over 11 years
      @loganfsmyth This gives me the same response as using session.user which is user is not defined
  • germainelol
    germainelol over 11 years
    Not sure I follow sorry, I'm kind of new to learning nodejs and all of its features. I'm connecting to my mongodb database like so: mongoose.connect('mongodb://localhost/testdb'); But I'm not sure how to check against the database, or what to put where you have put aUserIdOrUserObject. Assuming all of this eventually works, how would you recommend checking this in the view? I read the links but they look like the matrix to me in some cases!
  • topek
    topek over 11 years
    I think your view code is fine. It's the login logig you are missing. If you are just trying to start you could use passportjs.org or another authentication package nodetoolbox.com/categories/Authentication . This should get you started easily. Another link that might help: stackoverflow.com/questions/3498005/…
  • germainelol
    germainelol over 11 years
    I keep reading about passport indeed. But my problem is taking the passport logic and applying it to my program which I have taken from here by the way and started editing https://github.com/ric03uec/nodeblox/tree/tutorial_5 I seem lost.
  • topek
    topek over 11 years
    I think the only problem you are facing is that you are trying to achieve too much in one step. Maybe you should step back and just start with some basic login form (user, password), send it to a route like in my answer, check it against some predefined variables and set a session.user, if the credentials are correct. At this step you have a logged in user and can play around in the view. Later you can come back to your login logik and refine it. It's better to have something working now, than get stuck in other libraries code and give up.
  • germainelol
    germainelol over 11 years
    I thought the login logic was quite simple, if a user is logged in => print their username instead of login form. If not logged in => show login form. But my problem is simply what code to put in app.js in order for my view to know if I am logged in or not, I've searched everywhere and no help is really found, only examples where no one says where exactly to put the code :/
  • topek
    topek over 11 years
    You do not need much more code than on this screen. With the post to the /login route you set a session variable. This session variable can be used on successive request to switch between logged in and logged out users in the view. The only part missing is a route where you display your view. `app.get('/, function(req, res){res.render('index', {user: req.local.user}) and in your view you can use the user variable.
  • germainelol
    germainelol over 11 years
    I have updated the original code with the /login post from index.js which is validating the user correctly? So the post is successfully set to the user with req.session.user = user. But the app.get part you posted. Where should I be putting this?
  • germainelol
    germainelol over 11 years
    ` app.get('/', function(req, res){ res.render('index', { user: req.local.user }) });` I have made sure this is on the index.js page, but this gives error cannot read property user of undefined Where or how should I be defining this? Sorry to pester you.
  • topek
    topek over 11 years
    this should be done in your middleware. Put a console log in your middleware and make sure it gets run.
  • germainelol
    germainelol over 11 years
    http.createServer(app).listen(app.get('port'), function(){ console.log("Express server listening on port " + app.get('port')); app.get('/', function(req, res){ res.render('index', {user: req.local.user}) }); }); I should add it here? By middleware I understand this is where I'm making a connection of some sort to the server so I assume you mean here, where user is still not defined. I will try other places but I don't follow.
  • topek
    topek over 11 years
    middleware is where you set res.locals.user = req.session.user;
  • germainelol
    germainelol over 11 years
    app.use(function(req, res, next){ res.locals.user = req.session.user; next(); }) app.get('/', function(req, res){ res.render('index', {user: req.local.user}) }); Yep I now have this, but I still get the same error that I have not defined user :/ All your help is appreciated also I would like to add...
  • topek
    topek over 11 years
    put a console.log("this should be called");before res.locals.user and watch your console, if the function is really called.
  • germainelol
    germainelol over 11 years
    No I just see Express server listening on port 3000 and if I try to go to localhost:3000 I get the same errors again.
  • germainelol
    germainelol over 11 years
    Not sure what to change after playing around with where to put different things
  • topek
    topek over 11 years
    Could you try to put that middleware before app.use(express.router). I'm not quite sure on this, but I think that I had once a similar problem.
  • germainelol
    germainelol over 11 years
    Hi, I have tried putting app.use(app.router); both at the end of app.configure and just after the this should be called function both giving the same error and not printing to the cmd window
  • germainelol
    germainelol over 11 years
    Thanks for reply, I have added the code I have for User.js under Schemas. This should work by itself? If you see the comments with the previous answer to the question, I am also trying to get the session working through his methods to no success yet
  • germainelol
    germainelol over 11 years
    Where/how are you defining config.sessionSecret, config, memoryStore and viewUtils?
  • Renato Gama
    Renato Gama over 11 years
    That values are not relevant, you can ignore them. They are not useful in the session configuration (except for the MemoryStore and MongoStore). Config is an object with project specific configuration, memoryStore is the default way of saving session objects to memory (not useful for production)
  • germainelol
    germainelol over 11 years
    Yep I don't follow with MemoryStore sorry. I'm only trying to get my code to work to pass the user's username to the view when they are logged in. At the moment I can't even get the app to run because of errors I don't understand how to fix sorry.
  • germainelol
    germainelol over 11 years
    app.get('/', function(req, res){ res.render('index', {user: req.local.user}) }); It is this user: that is not defined according to the errors
  • germainelol
    germainelol over 11 years
    I am getting an error of user not being defined here which occurs when I run the program, however I also have a console.log function which does not print in the console as you see in the comments in the other question. ` app.get('/', function(req, res){ res.render('index', {user: req.local.user}) });`
  • germainelol
    germainelol over 11 years
    I only have the problem of it not recognising session.user, I have an index.js, login.js and User.js in order to validate the user's login details, but where should I be setting the session once they are logged in so that the view can print their username? I have added index.js to the OP
  • Renato Gama
    Renato Gama over 11 years
    Take a look at my new edit. Not sure if is it what youre looking for. Hope it helps!