Reputation: 133
I'm using a scotch.io tutorial on setting up PassportJS local login for an app I'm working on. After setting up my signup/login pages, MongoDB, PassportJS, I tried making a test "account", and.... nothing happens. No redirect, no flash message, nothing. It seems like nothing is getting picked up to post to the database. I'm including the pertinent scripts below. I tried to be as faithful as possible to the tutorial layout (source: https://scotch.io/tutorials/easy-node-authentication-setup-and-local).
index.js (entry point for server)
// load dependencies
var express = require('express');
var app = express();
var path = require('path');
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var LocalStrategy = require('passport-local').Strategy;
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var configDB = require('./config/database.js');
// setup views
var ejs = require('ejs');
var engine = require('ejs-locals');
//database configuration
mongoose.connect(configDB.url);
require('./config/passport')(passport);
app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
//view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use('/public', express.static(path.join(__dirname, 'public')));
// required for passport
app.use(session({
secret: 'ilovescotchscotchyscotchscotch',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // for flash messages stored in-session
// routes
require('./routes')(app, passport);
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
});
passport.js (passport settings)
var LocalStrategy = require('passport-local').Strategy;
var User = require('../user');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email': email }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'That e-mail address is already taken.'));
} else {
var newUser = new User;
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(req, email, password, done) {
User.findOne({ 'local.email': email }, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, req.flash('loginMessage', 'User not found.'));
if(!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Invalid password, please try again.'));
return done(null, user);
});
}));
};
/config/database.js
module.exports = {
'url': 'mongodb://localhost:27017/users/'
}
routes.js
module.exports = function(app, passport) {
app.get('/', function (req, res) {
res.render('pages/index');
});
app.get('/login', function (req, res) {
res.render('pages/login', { message: req.flash('loginMessage') });
});
app.get('/signup', function (req, res) {
res.render('pages/signup', { message: req.flash('signupMessage') });
});
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
}));
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user: req.user
});
});
app.get('/addroom', function (req, res) {
res.render('pages/addroom.ejs', {
message: req.flash('addroomMessage')
});
});
app.get('/propconfig', function (req, res) {
res.render('pages/propconfig.ejs', {
message: req.flash('propconfigMessage')
});
});
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
// route middleware to ensure a user is logged in
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
user.js (user schema)
// load dependencies
var mongoose = require('mongoose');
var bcrypt = require('bcrypt');
// define user schema
var userSchema = mongoose.Schema({
local: {
email: String,
password: String
}
});
// METHODS
// generating a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// creating model for user to expose to app
module.exports = mongoose.model('User', userSchema);
and finally, signup.ejs (template for signup UI)
<!doctype html>
<html>
<head>
<title>Node Authentication</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <!-- load bootstrap css -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
<style>
body { padding-top:80px; }
</style>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span> Signup</h1>
<!-- show any messages that come back with authentication -->
<% if (message.length > 0) { %>
<div class="alert alert-danger"><%= message %></div>
<% } %>
<!-- LOGIN FORM -->
<form action="/signup" method="post">
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email" id="email">
<div id="emailError"></div>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" id="password">
<div id="passwordError"></div>
</div>
<button type="submit" class="btn btn-warning btn-lg">Signup</button>
</form>
<hr>
<p>Already have an account? <a href="/login">Login</a></p>
<p>Or go <a href="/">home</a>.</p>
</div>
</div>
<script type="text/javascript" src="../public/javascripts/validate.js"></script>
</body>
</html>
Update: I commented out the email validation script I was using, and now the POST action is happening (why it wasn't before, I have no idea), but it's still not getting to the database.
Update #2: I tried running the server in debug mode. The console returned this information:
GET /signup 304 34.791 ms - -
express:router dispatching POST /signup +28s
express:router query : /signup +0ms
express:router expressInit : /signup +0ms
express:router logger : /signup +0ms
express:router cookieParser : /signup +1ms
express:router jsonParser : /signup +0ms
express:router urlencodedParser : /signup +3ms
express:router session : /signup +157ms
express:router initialize : /signup +2ms
express:router authenticate : /signup +0ms
express:router <anonymous> : /signup +1ms
POST /signup - - ms - -
express:router dispatching POST /signup +2m
express:router query : /signup +0ms
express:router expressInit : /signup +0ms
express:router logger : /signup +1ms
express:router cookieParser : /signup +1ms
express:router jsonParser : /signup +2ms
express:router urlencodedParser : /signup +0ms
express:router session : /signup +4ms
express:router initialize : /signup +1ms
express:router authenticate : /signup +2ms
express:router <anonymous> : /signup +1ms
POST /signup - - ms - -
Meanwhile, the browser stayed on "Waiting for localhost..."
for about 2 or 3 minutes (without crashing or timing out), before finally returning "The localhost page isn’t working
localhost didn’t send any data. ERR_EMPTY_RESPONSE"
Update #3: This is another debug log, checking all modules (not just Express):
express:router dispatching POST /signup +39s
express:router query : /signup +4ms
express:router expressInit : /signup +1ms
express:router logger : /signup +2ms
express:router cookieParser : /signup +5ms
express:router jsonParser : /signup +3ms
body-parser:json content-type "application/x-www-form-urlencoded" +0ms
body-parser:json skip parsing +4ms
express:router urlencodedParser : /signup +1ms
body-parser:urlencoded content-type "application/x-www-form-urlencoded" +0ms
body-parser:urlencoded content-encoding "identity" +3ms
body-parser:urlencoded read body +0ms
body-parser:urlencoded parse body +60ms
body-parser:urlencoded parse extended urlencoding +5ms
express:router session : /signup +8ms
express-session fetching 6M-W_9dEFDmsPBvNp2d0UmeBE9gDuXMn +14ms
express-session no session found +3ms
express:router initialize : /signup +9ms
express:router authenticate : /signup +0ms
express:router <anonymous> : /signup +2ms
req.body: {"email":"[email protected]","password":"pass1234"}
mquery findOne +20ms users { 'local.email': '[email protected]' } { fields: {} }
express-session saving EkaL4tXbUCZ9QXHDGt2XWxlgMjVGejAC +95ms
express-session split response +1ms
express-session set-cookie connect.sid=s%3AEkaL4tXbUCZ9QXHDGt2XWxlgMjVGejAC.cvTE1KsUvIzbnNqHP0ns9td75MUkR4mKRDvwuHk%2B4jE; Path=/; HttpOnly +4ms
morgan log request +17ms
POST /signup 302 237.147 ms - 58
express:router dispatching GET /signup +9ms
express:router query : /signup +2ms
express:router expressInit : /signup +0ms
express:router logger : /signup +1ms
express:router cookieParser : /signup +2ms
express:router jsonParser : /signup +0ms
body-parser:json skip empty body +0ms
express:router urlencodedParser : /signup +13ms
body-parser:urlencoded skip empty body +0ms
express:router session : /signup +1ms
express-session fetching EkaL4tXbUCZ9QXHDGt2XWxlgMjVGejAC +1ms
express-session session found +3ms
express:router initialize : /signup +1ms
express:router authenticate : /signup +1ms
express:router <anonymous> : /signup +1ms
express:view lookup "pages/signup.ejs" +6ms
express:view stat "/media/matt/PORTABLE/myapp/views/pages/signup.ejs" +1ms
express:view render "/media/matt/PORTABLE/myapp/views/pages/signup.ejs" +1ms
express-session saving EkaL4tXbUCZ9QXHDGt2XWxlgMjVGejAC +18ms
express-session split response +0ms
morgan log request +10ms
GET /signup 200 50.407 ms - 1736
Upvotes: 1
Views: 538
Reputation: 9818
Thanks for your code. I think it helped me fix this faster. I was able to reproduce your issue. Here is a diff of what I did to fix your issue
In routes.js, I modified passport to use local-signup
defined in passport.js instead of your existing function:
diff --git a/routes.js b/routes.js
index a6166b7..e2a742f 100644
--- a/routes.js
+++ b/routes.js
@@ -13,30 +13,12 @@ module.exports = function(app, passport) {
res.render('pages/signup', { message: req.flash('signupMessage') });
});
- app.post('/signup', function (req, res, next) {
- passport.authenticate('local', {failureRedirect: '/login'},
- function (req, email, password, done) {
- process.nextTick(function () {
- User.findOne({'local.email': email}, function (err, user) {
- if (err)
- return done(err);
- if (user) {
- return done(null, false, req.flash('signupMessage', 'That e-mail address is already taken.'));
- } else {
- var newUser = new User;
- newUser.local.email = email;
- newUser.local.password = newUser.generateHash(password);
- newUser.save(function (err) {
- if (err){
- throw err;}
- //res.redirect("/path")
- return done(null, newUser);
- });
- }
- });
- });
- });
-});
+ // process the signup form
+ app.post('/signup', passport.authenticate('local-signup', {
+ successRedirect : '/profile', // redirect to the secure profile section
+ failureRedirect : '/signup', // redirect back to the signup page if there is an error
+ failureFlash : true // allow flash messages
+ }));
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
Commented out few comments and made sure if err
is closed
diff --git a/config/passport.js b/config/passport.js
index dde7628..398796e 100644
--- a/config/passport.js
+++ b/config/passport.js
@@ -23,7 +23,6 @@ module.exports = function(passport) {
process.nextTick(function() {
User.findOne({ 'local.email': email }, function(err, user) {
if (err)
- console.log(err);
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'That e-mail address is already taken.'));
@@ -31,9 +30,9 @@ module.exports = function(passport) {
var newUser = new User;
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
- newUser.$__save(function(err) {
+
+ newUser.save(function(err) {
if (err)
- console.log(err);
throw err;
console.log(User);
console.log(newUser);
Here is a gif to show it is successful:
I have submitted a pull request to your branch.
Upvotes: 2
Reputation: 577
First change you local strategy like this
passport.use(new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function () {
//LocalStrategy verify callback
}
));
Then change you route /signup like this
app.post('/signup', function (req, res, next) {
passport.authenticate('local', {failureRedirect: '/login'},
function (req, email, password, done) {
process.nextTick(function () {
User.findOne({'local.email': email}, function (err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'That e-mail address is already taken.'));
} else {
var newUser = new User;
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function (err) {
if (err){
throw err;}
//res.redirect("/path")
return done(null, newUser);
});
}
});
});
})(req, res, next);
});
you can redirect to other pages from res.redirect("/path") like this
That route you defined in your routes i.e
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
it was not working because you can not define passport.authenticate directly in your routes, and you database connection is working fine it is fetching results from database no problem with database connection.
Upvotes: 3