When I submit a form whose contents are validated using express-validator I keep getting the error "req.checkBody is not a function" (and if I remove the line that generates that, I get other errors, like "req.sanitize is not a function"). It seems that express-validator is not being recognized properly so i thought of changing the current version and then I have uninstalled the current version and installed an older version#5.3.1 still It is showing the same error.
first I have required it in the main app.js file
var validator = require('express-validator');
Then I have used it like this for validation purpose
var User = require('../models/admin');
var LocalStrategy = require('passport-local').Strategy;
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) {
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Invalid password').notEmpty().isLength({min:4});
var errors = req.validationErrors();
if (errors) {
var message = [];
errors.forEach(function(error){
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email' : email}, function(err, user) {
if (err){
return done(err);
}
if (user){
return done(null, false, {message: 'email is already in use'});
}
var newUser = new User();
newUser.email = email;
newUser.password = newUser.encryptPassword(password);
newUser.save(function(err, result) {
if (err) {
return done(err);
}
return done(null, newUser);
});
});
}));
passport.use('local.signin', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true,
},function (req, email, password, done){
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Invalid password').notEmpty();
var errors = req.validationErrors();
if (errors) {
var message = [];
errors.forEach(function(error){
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email' : email}, function(err, user) {
if (err){
return done(err);
}
if (!user){
return done(null, false, {message: 'No user found!!'});
}
if (!user.validPassword(password)){
return done(null, false, {message: 'Wrong password!!'});
}
return done (null, user);
});
}));```
Related
I'm having a problem about verifying first my email address before i can login to my system . Here's my code so far.
This line of code is where i verify my email address when he clicks the link on his/her email address it will redirect to my login form.
router.get('/verify_email', function(req, res){
console.log('verify_email token: ', req.query.token);
User.findOne({authToken: req.query.token}, function(err, user){
if(err){
console.log(err);
} else {
console.log(user);
user.IsAuthenticated = true;
user.save(function(err){
if(err){
console.log(err);
} else {
console.log('Successfully updated user');
console.log(user);
sendgrid({
to: user.email,
from: 'pektospioneers.com',
subject:'Email COnfirmed!',
html: 'Thank you'
}, function(err, json){
if(err){
console.log(err);
} else {
console.log(json);
}
});
res.send(user);
}
});
}
});
req.flash("success_msg",'Email has been confirmed!');
res.redirect('/users/login');
});
and here's my usermodel
//new user in the model(user.js)
var newUser = new User({
name: name,
email: email,
authToken: authToken,
IsAuthenticated: false,
username: username,
password: password,
field: field,
e_money: e_money //temporary emoney
});
now the problem is here . I can still login directly after my registration even without confirming my email . so what should be the problem here sir/madame .
i tried the passportjs like this
passport.use(new LocalStrategy(
function(username, password, IsAuthenticated, done){
User.IfIsAuthenticated(IsAuthenticated, function(err, authenticated)}
if(err) throw err;
if(!authenticated){
return done(null, false, {message: 'Please confirm your email first'});
}
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
}
else{
return done(null, false, {message: "Invalid password"});
}
});
});
});
}));
but its not working it always says return done is not a function
and on my user.js it's just like this
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
/*
*need to know if authenticated or not
*so that if it is not yet authenticated
*the newly registered user cannot logged in
*/
module.exports.ifIsAuthenticated = function(IsAuthenticated, callback){
var query = {IsAuthenticated:IsAuthenticated};
User.findOne(query, callback);
}
By adding here this line of code i achieved what i want
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch && !User.email){
return done(null, false, {message: "Please confirm your email first!"});
}else if(isMatch && User.email){
return done(null, user);
}
else{
return done(null, false, {message: "Invalid password"});
}
});
Just need to answer this for the future reference of the others . Happy coding
in passport js, basic strategy, the following code sample provides a function for verifying the identity of a user.
passport.use(new BasicStrategy(
function(userid, password, done) {
User.findOne({ username: userid }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
Question is where (which file) in a Sails application should this code be placed? I suppose same applies for a custom verification function?
create AuthController under controllers directory
then write code to make passport handle login process
login: function(req, res) {
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message: info.message,
user: user
});
}
req.logIn(user, function(err) {
if (err) res.send(err);
return res.send({
message: info.message,
user: user
});
});
})(req, res);
this line passport.authenticate('local' will read configuration from passport.js inside config.js which will be like this :-
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(email, password, done) {
User.findOne({ email: email }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect email.' });
}
bcrypt.compare(password, user.password, function (err, res) {
if (!res)
return done(null, false, {
message: 'Invalid Password'
});
var returnUser = {
email: user.email,
createdAt: user.createdAt,
id: user.id
};
return done(null, returnUser, {
message: 'Logged In Successfully'
});
});
});
add these line into route.js :- 'post /login': 'AuthController.login'
I'm still a noob to node and webdev, but trying hard!
I get this error : can't set headers after they are sent
with the following while using passport.js and bcryptjs compare method for password validation on a mean stack
routes/login.js
var express = require('express')
var router = express.Router()
var mongoose = require('mongoose')
var User = mongoose.model('User')
var passport = require('passport')
router.post('/', function (req, res, next){
passport.authenticate('local', function(err, user, info){
if(err){ return next(err); }
if(user){
return res.json({token: user.generateJWT()});
} else {
return res.status(401).send(info)
}
})(req, res, next);
});
module.exports = router
authenticate/local.js
var passport = require('passport')
var LocalStrategy = require('passport-local').Strategy
var mongoose = require('mongoose')
var User = mongoose.model('User')
var bcrypt = require('bcryptjs')
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: {
username: 'Incorrect username.'
}
})
}
bcrypt.compare(password, user.password, function(err, isMatch) {
if (err) {
return done(err)
}
if (!isMatch) {
return done(null, false, {
message: {
password: 'Incorrect password'
}
})
}
});
return done(null, user);
});
}));
This validates correctly for a valid username and password, and logs in.
For an invalid username, it correctly rejects the login attempt.
But for an invalid password, it logs in and then crashes the app with the Can't set headers error.
However if i change the bcrypt.compare to bcrypt.compareSync, then all validations are correct.
if (!bcrypt.compareSync(password, user.password)) {
return done(null, false, {
message: {
password: 'Incorrect password'
}
});
}
I would rather not depend on the sync methods, so help me please understand where I am going wrong!
bcrypt.compare() is async but you're calling done(null, user) immediately. Move it inside the callback and it should be fine:
bcrypt.compare(password, user.password, function(err, isMatch) {
if (err) { return done(err) }
if (!isMatch) {
return done(null, false, { message: { password: 'Incorrect password' } })
}
done(null, user)
})
I'm making a form login by passportJs and it always return failureRedirect. I have search in stack overflow for this issue, but still not have the correct answer. Here is my code:
Form making form jade:
form(method='post', action='/users/login', enctype='multipart/form-data')
.form-group
label Username
input.form-control(name='username', type='text' placeholder='Enter Username')
.form-group
label Password
input.form-control(name='password', type='password' placeholder='Enter password')
input.btn.btn-default(name='submit', type='submit', value='Login')
Router Hanlde is using express framework form Nodejs and passport middleware:
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function(username, password, done) {
User.getUserByUsername(username, function(err, user) {
if (err) throw err;
if (!user) {
console.log('Unknown User');
return done(null, false, {
message: 'Unknown User'
});
}
User.comparePassword(password, user.password, function(err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
console.log('Invalid Password');
return done(null, false, {
message: 'Invalid Password'
});
}
});
});
}
));
router.post('/login', passport.authenticate('local', {
failureRedirect: '/users/login',
failureFlash: 'Invalid username or password'
}), function(req, res) {
console.log('Authentication Successful');
req.flash('success', 'You are logged in ');
res.redirect('/');
});
Looking at getUserByUsername function you shared in comments, it looks like you are not making call to callback function of getUserByUsername in correct way and therefore it is not getting user object resulting into failure redirect. The function you shared was:
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
Changing it to following should fix your issue:
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, function(err, user) {
callback(err, user);
});
}
I am using Passport on my node.js app and I am currently using an Username to login.
On my user register page, I have allow the user to register their unique username and email.
I want a login page with "Sign in Using username/email:" ________
Where the script can detect if there is a "#" in the field and look up the email instead of username.
I have tried for a few hours with no avail.
here is my passport.js
var mongoose = require('mongoose')
var LocalStrategy = require('passport-local').Strategy
var User = mongoose.model('User');
module.exports = function(passport, config){
passport.serializeUser(function(user, done){
done(null, user.id);
})
passport.deserializeUser(function(id, done) {
User.findOne({ _id: id }, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
}, function(username, password, done) {
User.isValidUserPassword(username, password, done);
}));
}
EDIT: below is the user.js as requested
var mongoose = require('mongoose');
var hash = require('../util/hash.js');
UserSchema = mongoose.Schema({
username: String,
email: String,
salt: String,
hash: String
})
UserSchema.statics.signup = function(username, email, password, done){
var User = this;
hash(password, function(err, salt, hash){
if(err) throw err;
// if (err) return done(err);
User.create({
username : username,
email: email,
salt : salt,
hash : hash
}, function(err, user){
if(err) throw err;
// if (err) return done(err);
done(null, user);
});
});
}
UserSchema.statics.isValidUserPassword = function(username, password, done) {
this.findOne({username : username}, function(err, user){
// if(err) throw err;
if(err) return done(err);
if(!user) return done(null, false, { message : 'Incorrect username.' });
hash(password, user.salt, function(err, hash){
if(err) return done(err);
if(hash == user.hash) return done(null, user);
done(null, false, {
message : 'Incorrect password'
});
});
});
};
var User = mongoose.model("User", UserSchema);
module.exports = User;
Ok, you should have something like this in your Mongoose model:
UserSchema.statics.isValidUserPassword = function(username, password, done) {
var criteria = (username.indexOf('#') === -1) ? {username: username} : {email: username};
this.findOne(criteria, function(err, user){
// All the same...
});
};
its a mongoose thing rather than a passport thing, and if you can try out this, using bredikhin's answer ^_^ :
var criteria = {$or: [{username: username}, {email: username}, {mobile: username}, {anything: username}]};
The key is to find a user through a query from mongodb!!!
In this way, you can have whatever query you want to find a user.
For sign ins with username OR email, you could also use passport-local-mongoose's findByUsername option modify the queryParameters
// add passport functions
// schema.plugin(passportLocalMongoose);
schema.plugin(passportLocalMongoose, {
// allow sign in with username OR email
findByUsername: function(model, queryParameters) {
// start
// // queryParameters => { '$or' : [ { 'username' : 'searchString' } ] }
// iterate through queryParameters
for( let param of queryParameters.$or ){
// if there is a username
if( typeof param == "object" && param.hasOwnProperty("username") ){
// add it as an email parameter
queryParameters.$or.push( { email : param.username } );
}
}
// expected outcome
// queryParameters => { '$or' : [ { 'username' : 'searchString' }, { 'email' : 'searchString' } ] }
return model.findOne(queryParameters);
}
});
its very simple you have to redefine the passport strategy your self, just like in the code below,
serialize with username
passport.serializeUser(function(user, done) {
done(null, user.username);});
deserialize with username
passport.deserializeUser(function(username, done) {
User.findOne({username:username},function(err, user){
done(err,user);
}); });
Passport Strategy
//passport strategy
passport.use(new LocalStrategy(function(username, password, done) {
console.log(username.includes("#"));
User.findOne((username.includes("#"))?{email:username}:{username:username}, function(err, user) {
if (err) {return done(err); }
if (!user) {console.log("i am ERROR"); return done(null, false, { message: 'Incorrect username.' });}
if (user.password===password) {return done(null, user); }
return done(null, false);
});
}
));
NOTE: Here user.password===password means that the password in database is stored as plaintext.. And you have to insert password manually to database such as password : req.body.password also you have to apply encryption and decryption user self before adding or in comparing.
Or you just make a middle-ware to handle the situation like so:
const User = require("../models/user");
var middlewareObj = {};
middlewareObj.checkUsername = function (req, res, next) {
if (req.body.username.indexOf('#') !== -1) {
User.findOne({ email: req.body.username }, (err, foundUser) => {
if (err || !foundUser) {
req.flash('error', 'Please check your username or password');
return res.redirect('/login');
} else {
req.body.username = foundUser.username;
next();
}
});
} else {
next();
}
}
module.exports = middlewareObj;
And simply add it to the login route:
app.post('/login', middleware.checkUsername, function (req, res, next) {
//Login logic goes here
}