Search code examples
javascriptajaxnode.jspassport.jspassport-local

nodejs not accept form data by ajax


I'm working with node 4.3.1, express 4.13.1 and an authentication tool is the local-passport. I'm trying to post login form data by ajax. so I want to show error message without page refresh. but the first step is killing me.

view:

<form id="login_form" action="#">
    <input type="hidden" id="csrf" name="_csrf" value="{{_csrfToken}}">
        <input id="email" name="email" type="email" placeholder="Email">
        <input id="password" name="password" type="password" placeholder="Password">
        <button type="" id="forLogin">Login</button>
    </form>
//POST Ajax
$('#forLogin').on('click', function(e){
    e.preventDefault();
    var data= {};
    data.email = $('#email').val();
    data.password = $('#password').val();
    data._csrf = $('#csrf').val();

    $.ajax({
        type: 'POST',
        url: '/login',
        data: JSON.stringify(data),     //  node.js accepts request but responds 403

//      data: $('#login_form').serialize(),
//          don't accept any request
        dataType: 'json',
//      headers: {'X_CSRF_TOKEN':'{{_csrfToken}}'},
//          not working too
        success: function(result){
                console.log('success');
                if(!result){
                    console.log('No result');
                }
            },
            error: function (xhr, ajaxOptions, thrownError) {
                console.log(xhr.status);
                console.log(thrownError);
            }
        });
    });

If I use data: JSON.stringify(data) , the firefox inspector shows very suspicious parameter: {"email":"test@gmail.com","password":"test","_csrf":"wOEsa4s2-I9dmSQuT9djm0kyrrp9WcZWj6U0"}:"" Even if this parameter passes well, I'm not sure it will work.

and In these cases: data: $('#login_form') or data:data

I don't get any response. but parameters seems plausible and key: attr pairs look neatly.

router.js

router.post('/login', function(req, res, next){
passport.authenticate('local-login', function(err, user, info){
console.log(req.body);

if (err) { return next(err); }
if (!user) {
    console.log('authentication fail');
    return res.json({ajaxMsg: 'authentication fail'});
}
req.logIn(user, function(err) {
  if (err) { return next(err); }
  // Redirect if it succeeds
  return res.redirect('/');
    });
  })
});

passport.js

var passport = require('passport'),
    LocalStrategy = require('passport-local').Strategy,
    User = require('../models/User.js'),
    bcrypt = require('bcrypt');

passport.serializeUser(function(user, done){
    done(null, user.email);
});
passport.deserializeUser(function(email, done){
    User.findOne(email, function(err, user){
        done(err, user);
    });
});
passport.use('local-login',
             new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true
},
    function(req, email, password, done){
    User.findOne({'email': email}, function(err, user){
        if(err) return done(err);
        if(!user){
            console.log('wrong email');
            req.flash('email', req.body.email);
            return done(null, false, req.flash('error_messages', 'No user found'));
        }
        if(!user.authenticate(password)){
            console.log('wrong password');
            req.flash('email', req.body.email);
            return done(null, false, req.flash('error_messages', 'Password does not Match'));
        }
        console.log('Login Success');
        return done(null, user);
    });
})
);
module.exports = passport;

I realized that there is no way to use connect-flash message without page refresh so I trying to replace other logics It's hard to understand how done() method works


Solution

  • I solved the problem.

    router.post('/login', function(req, res, next) {
      if(req.body.email.length == 0 || req.body.password.length == 0) {
        return res.json({error: 'enter a id and a pw'});
      }
      passport.authenticate('local-login', function(err, user, info) {
        if (err) { 
          return res.json({srverror: err}); 
        }
        // Redirect if it fails
        if (!user) {
          return res.json({error: info.msg});
        }
        if (user) {
          req.logIn(user, function(err) {
            if (err) { return res.json({srverror: err}); }
            // Redirect if it succeeds
            res.send({redirect: '/'});
          });
        }
      })(req, res, next);
    });
    

    (req, res, next) is the code I needed. but I cannot fully understand why It works.