I build an application using Passport lib using this tutorial (part of it).
Note, I don't need a registration, only login form.
One of the issues is that my LocalStrategy callback is never called. For storing I use mongo:
mongoose.connect(dbConfig.url, {
useMongoClient: true
});
//dbConfig
module.exports = {
'url' : 'mongodb://localhost/passport'
}
Login route looks like this:
module.exports = function(app, passport) {
app.get('/login', function(req, res) {
res.render('login', {
message: req.flash('loginMessage')
});
});
app.post('/login', passport.authenticate('login', {
successRedirect: '/', // redirect to the secure profile section
failureRedirect: '/login', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
}));
}
Passport logic is:
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('login', new LocalStrategy({
passReqToCallback: true
}, function(req, username, password, done) {
console.log('start'); // never called
User.findOne({
'local.email': email
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (!user.validPassword(password)) {
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
}
return done(null, user);
});
}));
};
console.log('start'); is never called, although passport.authenticate('login' ...) is called.
What can be an issue?
I finally fixed it and everything works. In case anyone face the same issues I'm posting here several problems and solutions.
The req.body was empty in my app.post, because I didn't add body parser. Fixed it with:
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
Username field was empty all the time because I named it as email and passport expected username. Fixed with:
new LocalStrategy({
usernameField: 'email', // this parameter
passReqToCallback: true
}
Related
I got some issues with a Node Express app. It will not redirect when I removed successRedirect property in auth method by passport.
The code below will not redirect to the desired page if I removed the successRedirect, and replacing it with a callback funtction.
The default code from defaultController.js
// passport local strategy
passport.use(new LocalStrategy({
usernameField: 'email',
passReqToCallback: true,
}, (req, email, password, done)=>{
User.findOne({ email:email }).then(user=>{
if(!user){
return done(null, false, req.flash('error-message', 'User not found with this email.'));
}
bcrypt.compare(password, user.password, (err, passwordMatched)=>{
if(err){
return err;
}
if(!passwordMatched){
return done(null, false, req.flash('error-message', 'Invalid username or password.'));
}
return done(null, user, req.flash('success-message', 'Login successful'));
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
router.route('/login')
.get(defaultController.login)
.post(passport.authenticate('local', {
successRedirect: '/admin',
failureRedirect: '/login',
failureFlash: true,
successFlash: true,
session:true,
}), defaultController.loginPost);
And this is what I would like to apply, but it seems it won't work and stuck in a infinite loading on chrome, however on console, it can receive an output:
here’s the output from the console
router.route('/login')
.get(defaultController.login)
.post(passport.authenticate('local', {
// successRedirect: '/admin',
failureRedirect: '/login',
failureFlash: true,
successFlash: true,
session:true,
}), (user)=>{
console.log(user.user.role);
if(user.user.role === 'admin'){
defaultController.loginPost;
}else{
console.log('hi');
}
});
As additional information, here is snippets defaultController that is responsible for handling the request:
login: (req,res)=>{
console.log();
res.render('default/login')
},
loginPost: (req,res)=>{
console.log(req.body.username);
res.render('/admin')
},
Any help?
you should use redirect instead of render so do like this:
login: (req,res)=>{
console.log();
res.redirect('default/login')
},
loginPost: (req,res)=>{
console.log(req.body.username);
res.redirect('/admin')
},
Assuming I have required passport, bcrypt, express-sessions and mysql correctly this code is supposed to add the user info to the session. I cannot for the life of me work out where it is going wrong.
App.js file
passport.use('local', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true //passback entire req to call back
}, function(req, email, password, done) {
connection.query("SELECT * FROM accounts WHERE email = ?", [email], async(err, rows, fields) => {
//if an error occurrs in mysql
if (err) {
return done(null, false)
connection.end()
}
//if there are no matching entries
if (!rows.length) {
console.log('invalid email')
return done(null, false)
connection.end()
}
//if the passwords don't compare
if (!(await bcrypt.compare(password, rows[0].password))) {
console.log('incorrect password')
done(null, false)
connection.end()
}
//if none of that happens
req.session.user = rows[0]
console.log('logged in')
connection.end()
});
}));
//handles de/serialization of the user data (all integrated from passport docs)
passport.serializeUser(function(user, done) {
return done(null, user.id)
console.log(user.id + "serialized")
});
passport.deserializeUser(function(id, done) {
connection.query("SELECT * FROM accounts WHERE id = " + id, function(err, rows) {
console.log('done' + rows[0])
return done(err, rows[0])
});
});
Auth route code
router.post('/auth', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/account'
}));
The code logs the user in, which is logged in the console, then logs them out again with a failure redirect to /account. I don't know where the authentication is going wrong, thanks for any replies in advance!
You can achieve the same using express-session..
install express-session: npm i express-session --save
Require it in your node application: var session = require('express-session');
Configure: app.use(session({ secret: "YourSecretKeyGoesHere", saveUninitialized: true, resave: true }));
And then check your session..
Okay so I have implemented passportjs EXACTLY like my other projects which work perfectly, but for some reason in my current project I just cant get it to success/failure redirect.
Here's my code
route
app.post('/login', passport.authenticate('login', {
successRedirect: '/#1',
failureRedirect: '/#2',
failureFlash: true
}));
app.post('/login',
passport.authenticate('login', {failureRedirect: '/login'}),
function (req, res) {
console.log("logged");
res.redirect('/#1');
});
^ I tried it two different ways,in the second way, the 'logged' did not get logged..
Passport
//SIGN IN
passport.use('login', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true
},
function (req, username, password, done) {
User.findOne({'username': username}, function (err, user) {
console.log("found: " + user);
if (err) {
console.log(err);
}
if (!user) {
return done(null, false, req.flash('message', 'Username not in DB'));
}
if (!user.checkPass(password)) {
return done(null, false, req.flash('message', 'Incorrect Password'));
}
//return user if all of the above pass
return done(null, user);
});
}));
EDIT: the passport code does work well, meaning it goes right towards the end and I can console.log the correct user.
I have made a small login application using Express and Passport. But it seems I can't direct the user into a specific userprofile. What has to happen is, the user fills up an HTML form, and he has to get redirected to his own profile page (For the sake of simplicity, lets say that page differs from other user pages only in terms of the title). I have this in my user routes. (i.e. routes/users.js)
router.get('/userprofile', authenticationMiddleware(), function (req,
res, next) {
res.render('userprofile');
});
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/users/userprofile',
failureRedirect: '/users/login',
failureFlash: true
}));
In my passport.js config file I have this.
passport.use('local-login', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true
}, function (req, username, password, done) {
db.pool.getConnection(function (err, connection) {
if(err) throw err;
var query = connection.query('SELECT * from users WHERE username = ?', username, function (err, rows) {
if(err) return done(err);
if(!rows.length) {
return done(null, false, req.flash('loginMessage', 'No User Found'));
}
//Comparing passwords using bcrypt
bcrypt.compare(password, rows[0].password, function(error, res){
if(res){
return done(null, rows[0]);
} else {
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
}
});
});
});
}));
What I need to do is get the username from the form, and pass it to the successRedirect attribute in passport.authenticate, and then I can modify the get method adding a route parameter like '/users/:username' and render 'username' view.
How can I do this?
EDIT:
I did something like this.
router.get('/userprofile/:username', authenticationMiddleware(), function (req, res, next) {
res.render('userprofile', {
username: req.params.username,
title: 'Welcome, '+ req.params.username
});
});
router.post('/login', function (req, res, next) { //Testing callback.
console.log("Username is: " + req.body.username);
passport.authenticate('local-login', {
successRedirect: '/users/userprofile/' + req.body.username,
failureRedirect: '/users/login',
failureFlash: true
})(req, res);
next();
});
This works on some attempts. However, it returns this error sometimes.
POST /users/login 404 43.741 ms - 5226 /home/dasun/WebstormProjects/schoolentry/node_modules/passport/lib/middleware/authenticate.js:249
if (err) { return next(err)};
How can I get rid of this error?
Thanks.
Found the answer. I have missed next in POST method in /login route.
i.e. I should write
router.post('/login', function (req, res, next) { //Testing callback.
console.log("Username is: " + req.body.username);
passport.authenticate('local-login', {
successRedirect: '/users/userprofile/' + req.body.username,
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
I am trying to do a basic username/password authentication using passport.js and passport local.
While failureRedirect does exactly what it is supposed to do, (redirects to a specified page), successRedirect keeps pending with the request for its specified page, and after some time, it returns empty response.
http://www.deviantpics.com/VdG
As you can see in this picture, when it is requesting dashboard, it says that its size is 0B, but when I go on that dashboard without redirecting it says it has 1.6B.
I have looked all over Stackoverflow, and I couldn't find an answer that would help me.
Could you please check my code and suggest something before I go berserk?
This is passport load code
//set expression
var expressSession = require('express-session');
app.use(expressSession({
secret: credentials.session.secret
}));
//set passport
var passport = require('passport');
var localStrategy = require('./strategies/auth/local.js');
passport.use('local', localStrategy);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.use(passport.initialize());
app.use(passport.session());
routes.js
module.exports = function(app) {
//main
app.get('/', main.home);
app.get('/login', main.login);
app.get('/signup', main.signup);
app.post('/login', auth.loginLocal);
app.post('/signup', main.checkSignup);
//user
app.get('/user/dashboard', user.dashboard);
app.get('/user/addmemory', user.addMemory);
app.get('/user/memory', user.memory);
login function
exports.loginLocal = passport.authenticate('local', {
successRedirect: '/user/dashboard',
failureRedirect: '/login'
});
local strategy
var localAuthStrategy = 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);
});
});
dashboard function
exports.dashboard = function(req, res) {
res.render('user/dashboard', {
layout: 'user'
});
};
I found an answer to my question, the problem was that the User model was not defined in the script where serializeUser and deserializeUser were defined.
I could not figure out what was going on, because I did not define any action in catch all handler, so a thing to remember, make sure to have catch all handler defined to know what is happening
app.use(function(err, req, res, next) {
console.log(err);
});
I was facing the same problem as your a few days back and what I found was that I forgot to put parenthesis at the end of the serializeUser and deserializeUser functions.
I was actually using the passport-local-mongoose package for the respective functions. But it must be noted that in app.use() the functions are called and executed for all the template files so, we do use parenthesis with the names of the functions.