PassportJs Authentication Infinite Loop and Execut

2019-07-16 04:30发布

问题:

I am trying to build the authentication system using PassportJs and Sequelize. I made the registration system by myself, using Sequelize. I want to use PassportJS only for Login.

It does not redirect me to the failureRedirect route, neither to the SuccessRedirect one, but when submitting the form it enters into an endless loop and in my console, the following message appears:

 Executing (default): SELECT `id`, `username`, `lastName`, `password`,  `email`, `phone`, `createdAt`, `updatedAt` FROM `user` AS `user` LIMIT 1;   

My project is structured in: users_model.js , index.js and users.js (the controller).

The code I have in my index.js looks like this:

//===============Modules=============================
var express = require('express');
var bodyParser = require('body-parser');   
var session = require('express-session');
var authentication= require('sequelize-authentication');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var passportlocal= require('passport-local');
var passportsession= require('passport-session');

var User = require('./models/users_model.js');


passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function(err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));


passport.serializeUser(function(user, done) {
  done(null, user.id);
});

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


var users= require('./controllers/users.js');    
var app = express();


app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');


app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.use('/users', users);
app.use('/events', events);

//-------------------------------------------Setup Session------------
app.use(session({
    secret: "ceva",
    resave:true,
    saveUninitialized:true,
    cookie:{},
    duration: 45 * 60 * 1000,
    activeDuration: 15 * 60 * 1000,
}));


// Passport init
app.use(passport.initialize());
app.use(passport.session());

//------------------------------------------------Routes----------
app.get('/', function (req, res) {
     res.send('Welcome!');
});

   //-------------------------------------Server-------------------

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

In my controller, I made the registration system by myself, using Sequelize. In users.js, I have:

var express = require('express');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var passportlocal= require('passport-local');
var passportsession= require('passport-session');
var router = express.Router();

var User = require('../models/users_model.js');

//____________________Initialize Sequelize____________________

const Sequelize = require("sequelize");
const sequelize = new Sequelize('millesime_admin', 'root', '', {
  host: 'localhost',
  dialect: 'mysql',
  pool: {
    max: 5,
    min: 0,
    idle: 10000
  }
}); 

//________________________________________


router.get('/',function(req,res){
res.send('USERS');
});

router.get('/register', function(req, res) {
     res.render('registration', {title: "Register" });
});

router.post('/register', function(req, res) {
    var email = req.body.email;
    var password = req.body.password;
    var username= req.body.username;
    var lastname= req.body.lastname;
    var phone= req.body.phone;

   User.findAll().then(user => {
    usersNumber = user.length;
    x=usersNumber+1;
    var y =usersNumber.toString();
    var uid='ORD'+ y;

    User.sync().then(function (){
      return User.create({
      id:uid,
      email: email,
      password:password,
      username: username,
      lastName: lastname,
      phone: phone,
         });
    }).then(c => {
        console.log("User Created", c.toJSON());
         res.redirect('/users');
    }).catch(e => console.error(e));    
 });    
});

router.get('/login',function(req,res){
    res.render('authentication');
});

//router.post('/login', function(req, res, next) {
//    console.log(req.url);  // '/login'
//    console.log(req.body);
// I got these:{ username: 'username', password: 'parola' } 
//    passport.authenticate('local', function(err, user, info) {
//        console.log("authenticate");
//        console.log('error:',err);
//        console.log('user:',user);
//        console.log('info:',info);
//    })(req, res, next);
//});


router.post('/login', passport.authenticate('local', { 
    successRedirect: '/events',                    
    failureRedirect: '/users/register' 
    }));

router.get('/logout', function(req, res){
    req.logout();    
    res.redirect('/users/login');
});    

//__________________________________________
module.exports = router;

回答1:

Main problem: not an infinite loop, but incorrect usage of Sequelize

This is not an infinite loop but just a hanging response from the server which would be ended with a timeout error.

When you do this:

passport.use(new LocalStrategy(
  function(username, password, done) {
    ...
  }
));

...passport and express wait for the done function to be called. Once it's done(), they go forward in the middleware chain and send the response to the client.

The done function is not called, because Sequelize seems to not support callback functions, but promises. So, the correct way to call Sequelize methods is:

User.findOne({ username: username }).then(user => {
  if (!user) {
    return done(null, false, { message: 'Incorrect username.' });
  }
  if (!user.validPassword(password)) {
    return done(null, false, { message: 'Incorrect password.' });
  }
  done(null, user);
}).catch(err => done(err));

(de)Serializing the session user

Seems that there is no id field in the user instances, but userid. Therefore we have to do:

passport.serializeUser(function(user, done) {
  done(null, user.userid);
});

passport.deserializeUser(function(id, done) {
  User.findOne({ userid: id }).then(user => {
    done(null, user);
    console.log(id);
  }).catch(err => done(err));
});

For reference, this commit fixes these issues.