Search code examples
javascriptnode.jslogoutpassport-local

Node js logout instruction isn't running in a serial way


eI'm using:

  • framework: express
  • template engine :handlebars
  • authentification: passport / passport-local

So login process goes well, but in logout i have a problem:

//routes/users.js
//logout 
router.get("/logout",(req,res)=>{
    req.logout();
    req.flash("success_msg","You are logged out");
    console.log(req.user);
    res.render("users/login");  
});


//views/users/login.js
{{user}} 

//app.js:
// Setting Global variables:
app.use(function(req,res,next){
    res.locals.success_msg = req.flash("success_msg");
    res.locals.error_msg = req.flash("error_msg");
    res.locals.error = req.flash("error");
    res.locals.user = req.user || null;
    next();
});

So the probleme is that when i clic on logout, i'm redirected to login view but the user object still there(not null),and when I refresh the user is initialised to null,

So my problem why the user haven't been set to null before refirection ?

Full files codes :(app.js, routes/users.js, /config/passport.js)

* app.js 

    const express = require('express');

    const methodOverride = require('method-override');
    const mongoose = require('mongoose');
    const exphbs  = require('express-handlebars');
    const bodyParser = require('body-parser');
    const flash = require('connect-flash'); 
    const session = require('express-session');
    //const path = require("path");

    const passport = require('passport');


    const app=express();

    // load routes :
    const ideas = require("./routes/ideas");
    const users = require("./routes/users");

    //---------------Mongoose Connect-----------------------

    //Map global promise = get rid of warning
    mongoose.Promise = global.Promise;
    //Connect to mongoose
    mongoose.connect('mongodb://localhost/vidjot-db',{
        useMongoClient: true
    })
    .then(function(){
        console.log("MongoDB connected ...");
    })
    .catch(err => console.log(err));

    //----------------Middlewares set in Use-----------------

    // Static folder Set:
    //app.use(express.static(path.join(__dirname,'public')));
    app.use(express.static('public'));

    // Session middleware :
    app.use(session({
      secret: 'mySecret',
      resave: true,
      saveUninitialized: true,
      //cookie: { secure: true }
    }));

    // passport middleware :
    app.use(passport.initialize());
    app.use(passport.session());

    // handlebars middleware :
    app.engine('handlebars', exphbs({defaultLayout: 'main'}));
    app.set('view engine', 'handlebars');

    // body parser middleware :
    // parse application/x-www-form-urlencoded
    app.use(bodyParser.urlencoded({ extended: false }));
    // parse application/json
    app.use(bodyParser.json());

    //methodOverride middleware:
    app.use(methodOverride('_method'));

    //Connect flash middleware:
    app.use(flash());

    //----------------My Own Middlewares-----------------

    // Setting Global variables:
    app.use(function(req,res,next){
        res.locals.success_msg = req.flash("success_msg");
        res.locals.error_msg = req.flash("error_msg");
        res.locals.error = req.flash("error");
        console.log("res.locals.user");
        res.locals.user = req.user || null;
        next();
    });

    /* app.use(function(req,res,next){
        console.log("3ale rou7i");
        console.log(Date.now());
        req.att_x="karim";
        next();
    }) */

    app.use(function(req,res,next){
        console.log("hani ne5dem");
        next();
    });

    //-----------------Routes-----------------------------

    // Index Route:
    app.get("/",(req,res) => {
        res.render('index');
        //console.log("get callback");
    });

    // about Route:
    app.get("/about",(req,res)=>{
        res.render("about",{title:"about1"});
    });

    // Use routes :
    app.use("/ideas",ideas);
    app.use("/users",users);

    //--------------------------------------------------

    //call local-strategy:
    require("./config/passport")(passport);

    //--------------------------------------------------

    const port=5000;

    app.listen(port,()=>{
        console.log(`server started on port ${port}`);
    });


* routes/users.js:


    const express = require("express");
    const mongoose = require("mongoose");
    const bcrypt = require('bcryptjs');
    const passport = require("passport");

    const router = express.Router();

    //--------------------------------------------------

    // Load User Model:
    require('../models/User');
    const User = mongoose.model('Users');

    //--------------------------------------------------
    //login form
    router.get("/login",(req,res)=>{
        res.render("users/login");
    });
    //handle login form:
    router.post('/login',
      passport.authenticate('local', {
        successRedirect: '/ideas',
        failureRedirect: '/users/login',
        failureFlash:true,
      })
    );
    //logout 
    router.get("/logout",(req,res)=>{
        req.logout();
        req.flash("success_msg","You are logged out");
        console.log("routes users",req.user);
        res.render("users/login");  
    });

    //register form
    router.get("/register",(req,res)=>{
        res.render("users/register");
    });
    // handle register form
    router.post("/register",(req,res)=>{
        let errors=[];
        if(req.body.password != req.body.password2)
            errors.push({"text":"password do not match"});

        if(req.body.password.length < 4)
            errors.push({"text":"password must be at least 8 characters"});

        if(errors.length > 0)
            res.render("users/register",{
                errors:errors,
                name:req.body.name,
                email:req.body.email,
            });
        else{
            User.findOne({email:req.body.email})
            .then(user=>{
                if(user){
                    req.flash("error_msg","email already registred");
                    res.render("/users/login");
                }else{
                    const newUser = new User({
                        name:req.body.name,
                        email:req.body.email,
                        password:req.body.password,
                        date:req.body.date,
                    });

                    bcrypt.hash(newUser.password, 10, function(err, hash) {
                        if (err) throw err;
                        newUser.password=hash;
                        newUser
                        .save()
                        .then(user=>{
                            req.flash("success_msg","You are registered, You can connect Now");
                            res.redirect("/users/login");           
                        }).catch(err=>{
                            console.log(err);
                            return;
                        });       
                    });             
                }
            })
        }

    });

    //--------------------------------------------------

    module.exports = router;


* config/passport.js :

    const mongoose = require('mongoose');
    const bcrypt = require("bcryptjs");
    const LocalStrategy = require("passport-local").Strategy;
    const passport = require("passport");

    //-------------------------------------------------------

    // Load User Model:
    require('../models/User');
    const User = mongoose.model('Users');

    //-------------------------------------------------------

    module.exports=function(passport){

        passport.use(
        new LocalStrategy({usernameField:'email'},function(email, password, done){

            User.findOne({'email':email},function(err, user) {  
                if (err)
                    return done(err);
                if (!user)
                    return done(null, false,{message:"You are not registred"});
                if (!bcrypt.compareSync(password,user.password) ){
                    return done(null, false,{message:"Missing email or password !"});
                }
                return done(null, user);  
            });

        }));

        passport.serializeUser(function(user, done) {
            console.log("SERIALIZE");
            done(null, user.id);
        });

        passport.deserializeUser(function(id, done) {
            console.log("DESERIALIZE");
            User.findById(id, function(err, user) {
            done(err, user);
          });
        }); 
    }

Solution

  • You have middleware that set res.locals based on a logged in user for every request.

    Your res.render() template uses that res.locals data when rendering the page.

    When you call req.logout(), nobody clears the res.locals that were already set when the user was still logged in so res.locals.user is now inaccurate.

    So, when res.render() gets called after the logout, res.locals are still set as if the user is logged in and thus the page renders that way.

    A simple solution is to clear the locals when you logout so they don't wrongly indicate the user is still logged in:

    //routes/users.js
    //logout 
    router.get("/logout",(req,res)=>{
        req.logout();
        // clear user before rendering to indicate logged out
        res.locals.user = null;
        req.flash("success_msg","You are logged out");
        console.log(req.user);
        res.render("users/login");  
    });