Related
I have used bcryptjs to hash my passwords and the registration of the user takes place fine.
But when I try to login, the bcrypt.compare function returns a false promise if the passwords contain numbers or other characters.
Everything works fine if the password is just letters.
I have searched everywhere but could not find a solution for this error?
Here are my files :
users.js (MODEL)
var mongoose = require("mongoose");
var bcrypt = require("bcryptjs");
var userSchema = mongoose.Schema({
name: String,
email: String,
password: String,
products: [{
type: mongoose.Schema.Types.ObjectID,
ref: "Product"
}],
username: String
});
var User = module.exports = mongoose.model("User", userSchema);
module.exports.createUser = function(newUser, callback) {
bcrypt.genSalt(5,function(err,salt){
bcrypt.hash(newUser.password,salt,function(err,hash){
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
console.log(isMatch);
callback(null, isMatch);
});
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
app.js
app.use(passport.initialize());
app.use(passport.session());
var LocalStrategy = require("passport-local").Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({username: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) {
console.log("ERR1");
return done(err);
}
if(isMatch) {
console.log("MATCH");
return done(null,user);
} else {
console.log("NOT VALID");
return done(null, false, {message: 'Invalid password'});
}
});
});
}
));
passport.serializeUser(function(user,done){
done(null,user.id);
});
passport.deserializeUser(function(id,done){
User.getUserById(id, function(err,user){
done(err,user);
})
})
users.js (ROUTE)
router.post("/login", passport.authenticate('local', function (error, user, info){
if(error) {
console.error(error);
console.log('Failed login:');
}
if (user === false) {
console.log("user not found");
} else {
// handle successful login ...
console.log("logged in");
}
}), function (req, res) {
res.send(req.user);
});
router.post("/signup", function (req, res) {
console.log(req.body);
var password = req.body.password;
var password2 = req.body.password2;
if(password == password2) {
var newUser = new User ({
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.username
});
User.createUser(newUser, function(err, user){
if(err)
throw err;
console.log(user);
res.send(user).end();
});
} else {
res.status(500).send("{errors: \"Passwords don't match\"}").end()
}
});
Whenever I enter a password that contains numbers, I get
false
NOT VALID
user not found
I'm sorry if I have done or not done something extremely simple. This is my first time using bcryptjs.
All answers are appreciated!
In the users.js file at the comparePassword function inside the compare method of bcrypt you are throwing the error instead of passing it to the callback. Maybe if you make this change:
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
console.log(isMatch);
callback(err, isMatch);
});
}
You will see what kind of error it's generated by the case when you introduce numbers in your passwords.
I'm trying to make a login/sign up API with nodejs, express and mysql.
When testing it i don't get any errors and i get the "Succesful Sign Up!" message. When i check the database though, the user table is still empty.
Here's the query i'm trying to execute.
con.query("INSERT INTO user (unique_id, email, encrypted_password, salt, created_at, updated_at) VALUES (?,?,?,?,NOW(),NOW())",[uid, email, password, salt], function (err, result, fields) {
con.on('error', function (err) {
console.log('[MySQL ERROR]',err);
res.json('Resgister Error: ',err);
});
res.json('Succesful Sign Up!');
})
And here's the full code.
//Libraries
var crypto = require('crypto');
var uuid = require('uuid');
var express = require('express');
var mysql = require('mysql');
var bodyParser = require('body-parser');
//connection with MySQL
var con = mysql.createConnection({
host: "localhost",
user: "user",
password: "password",
database: "database",
});
//Encrypting password
var genRandomString = function (length) {
return crypto
.randomBytes(Math.ceil(length / 2))
.toString('hex')
.slice(0, length);
};
var sha512 = function (password, salt) {
var hash = crypto.createHmac('sha512', salt);
hash.update(password);
var value = hash.digest('hex');
return {
salt: salt,
passwordHash: value,
};
};
function saltHashPassword(userPassword) {
var salt = genRandomString(16);
var passwordData = sha512(userPassword, salt);
return passwordData;
}
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
//Sign up
app.post('/register/', (req, res, next) => {
var post_data = req.body;
var uid = uuid.v4();
var plaint_password = post_data.password;
var hash_data = saltHashPassword(plaint_password);
var password = hash_data.passwordHash;
var salt = hash_data.salt;
var email = post_data.email;
con.query("SELECT * FROM user where email=?", [email], function (err,result,fields) {
con.on('error', function (err) {
console.log('[MySQL ERROR]', err);
});
if (result && result.length)
res.json('User already exists');
else
{
con.query("INSERT INTO user (unique_id, email, encrypted_password, salt, created_at, updated_at) VALUES (?,?,?,?,NOW(),NOW())",[uid, email, password, salt], function (err, result, fields) {
con.on('error', function (err) {
console.log('[MySQL ERROR]',err);
res.json('Resgister Error: ',err);
});
res.json('Succesful Sign Up!');
})
}
});
})
//Login
app.post('/login/', (req, res, next) =>{
var post_data = req.body;
var user_password = post_data.password;
var email = post_data.email;
con.query("SELECT * FROM user where email=?", [email], function (err,result,fields) {
con.on('error', function (err) {
console.log('[MySQL ERROR]', err);
});
if (result && result.length)
{
var salt = result [0].salt;
var encrypted_password = result[0].encrypted_password;
var hashed_password = checkHashPassword(user_password,salt).passwordHash;
if(encrypted_password==hashed_password)
res.end(JSON.stringify(result[0]))
else
res.end(JSON.stringify('Wrong Credentials'))
}
else
{
res.json('Wrong Credentials')
}
});
})
app.listen(3000, () => {
console.log("RESTFul API running in port 3000");
});
Can try this and let me know if it works
con.query("INSERT INTO user (unique_id, email, encrypted_password, salt, created_at, updated_at) VALUES (?,?,?,?,NOW(),NOW())",[uid, email, password, salt], function (err, result, fields) {
if(err) {
console.log('[MySQL ERROR]',err);
res.json('Resgister Error: ',err);
}else {
res.json('Succesful Sign Up!');
}
})
I'm trying to deal with authentication sessions in Node.js, Express, Passport app.
I made lines of code to use express-session and it still can't auth even when I register new user.
Here is strategy.
// Local Strategy
passport.use(new LocalStrategy({ usernameField: 'email' }, function(username, password, done){
User.findOne({ 'email': username }, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {type: "danger", message: 'No user found'});
}
// Match Password
bcrypt.compare(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {type: "danger", message: 'Wrong password'});
}
});
});
}));
Here are serializers.
passport.serializeUser(function(user, done) {
console.log(user.id);
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log(user.id);
done(err, user);
});
});
Here is login and register route.
// Login page and form
router.get('/login', function(req, res) {
res.render('login');
});
router.post('/login', passport.authenticate('local',
{successRedirect: '/chat',
failureRedirect: '/login'}));
// Register page and form
router.get('/register', function(req, res) {
let errors = [];
res.render('register', { 'errors': '' });
});
router.post('/register', [
check('name').notEmpty().withMessage('Name field is empty'),
check('surname').notEmpty().withMessage('Surname field is empty'),
check('email').notEmpty().withMessage('E-mail is empty'),
check('password').notEmpty().withMessage('Password field is empty'),
check('password_confirm').notEmpty().withMessage('Password confirmation field is empty'),
check("password", "Passwords don't match")
.custom((value,{req}) => {
if (value !== req.body.password_confirm) {
throw new Error("Passwords don't match");
} else {
return value;
}
}),
], function(req, res) {
const { name, surname, email, password } = req.body;
let errors = validationResult(req);
console.log(errors.errors);
if(!errors){
res.render('register', { 'errors': errors.errors });
console.log('ebebe');
} else {
console.log('oooo');
let NewUser = new User ({
name, surname, email, password
});
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
NewUser.password = hash;
NewUser.save();
});
});
res.redirect('/chat');
}
});
Here is protected route.
router.get('/chat', (req, res) => {
if(req.isAuthenticated()) {
res.send('definitely secure page');
console.log(req.user);
console.log(req.isAuthenticated());
} else {
res.send('ebebe');
console.log(req.user);
console.log(req.isAuthenticated());
}
});
How to make it work properly and what am I doing wrong?
Here is a way to do it. You can use something like jsonwebtoken in combination with express-session and write a middleware function to check if the token is valid and use it to protect the routes that you want to protect. Here are some snippets of code that I hope will help guide you in the right direction.
First you can write a function like this in your UserSchema so you can use it later to generate a jwt token when the user logs in
var jwt = require('jsonwebtoken');
UserSchema.methods.generateJWT = function() {
var today = new Date();
var exp = new Date(today);
exp.setDate(today.getDate() + 60);
return jwt.sign({
id: this._id,
username: this.username,
exp: parseInt(exp.getTime() / 1000),
}, secret);
};
then in the login route you can use it to generate a token.
router.post('/login', passport.authenticate('local',
failureRedirect: '/login'}), function(req, res) {
req.user.token = user.generateJWT();
req.session.token = req.user.token;
res.redirect('/dashboard')
});
and then you can write the middleware
function auth(req, res, next) {
//console.log(req.session.token)
if (req.session.token) {
const token = req.session.token
let decoded = jwt.verify(token, secret)
console.log(decoded)
User.findById(decoded.id, function(err, user) {
if (err || !user) {
return res.redirect('/')
}
//console.log(user)
res.locals.user = user
req.user = user
next()
})
} else {
return res.redirect('/')
}
}
and then you can protect your routes with it
router.get('/protected', auth, function(req, res) {
})
I am working on a task with different modules.
I require a common mongodb connection for each and every module..
How can I write in some module and use in this because the db connection is also required in some other modules...
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
var dbo;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
dbo = db.db("mydb");
});
router.post('/', function(req, res) {
dbo.collection("customers").find({"userid":req.body.userid}).toArray(function(err, result) {
if (err) throw err;
if(result.length>0){
res.send("username already taken please enter differnt username ")
}
else if(req.body.fname==undefined||(!validator.isAlpha(req.body.fname))){
res.send("please enter only alphabets as fname ")
}
else if(req.body.lname==undefined||(!validator.isAlpha(req.body.lname))){
res.send("please enter only alphabets as lname ")
}
else if(req.body.userid==undefined||(!validator.isAlphanumeric(req.body.userid))){
res.send("please enter only alphanemric as user name ")
}
else if(req.body.pwd==undefined||req.body.pwd.length<6){
res.send("please enter atleast 6 charcaters as password ")
}
else{
var bcrypt = require('bcryptjs');
var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync(req.body.pwd, salt);
req.body.pwd=hash;
dbo.collection("customers").insertOne(req.body, function(err, res) {
if (err) throw err;
console.log("1 document inserted");
});
res.send(req.body);
}
});
});
module.exports = router;
use can use node export and import, to that you can use mongodb connection instance in other modules also,
assuming dbo is variable where you want to store mongodb connection
export let dbo;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
dbo = db.db("mydb");
});
you can assign db connection to dbo variable and and use it in whichever module you want
you have to create a middleware for your connection and then assign the db object to your request object ( req in your case )
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
router.use( (req,res,next) => {
MongoClient.connect(url, function(err, db) {
if (err) throw err;
req.dbo = db.db("mydb");
next();
});
})
in your router.post("/", ...) you will do req.dbo.collection(...)
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
var dbo=null;
exports.conection=function(){
if(dbo!=null) return
MongoClient.connect(url, function(err, db) {
if (err) throw err;
dbo = db.db("mydb");
});
}
exports.get = function (){
return dbo;
}
i tried this and i use get method when ever i require this is working for me
Hey I'm new to express and am trying to login as a user. With the following code, I get the error below. I thought since I did module.exports.comparePassword it would work. Is there something I'm missing? Thanks for any help
events.js:160
throw er; // Unhandled 'error' event
^
TypeError: user.comparePassword is not a function
at /Users/Sam/Desktop/teach/routes/users.js:112:17
at Query. (/Users/Sam/Desktop/teach/node_modules/mongoose/lib/model.js:3343:16)
at /Users/Sam/Desktop/teach/node_modules/kareem/index.js:259:21
at /Users/Sam/Desktop/teach/node_modules/kareem/index.js:127:16
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
models/user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcryptjs')
var userSchema = new Schema({
email: { type: String },
password: { type: String },
type: { type: String }
});
var User = mongoose.model('User', userSchema);
module.exports = User;
//Get a User by id
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
//Get a User by email
module.exports.getUserByEmail = function(email, callback){
var query = {email : email}
User.findOne(query, callback);
}
//Save a student
module.exports.saveStudent = function(newUser, newStudent, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash){
if (err) {throw err}
newUser.password = hash;
//Saves both a user and student
async.parallel([newUser.save, newStudent.save], callback);
})
})
}
//Save a instructor
module.exports.saveInstructor = function(newUser, newInstructor, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash){
if (err) {throw err}
newUser.password = hash;
//Saves both a user and instructor
async.parallel([newUser.save, newInstructor.save], callback);
})
})
}
//Checks if password matches.
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err) throw err;
callback(null, isMatch);
});
}
routes/users.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
var Student = require('../models/student');
var Instructor= require('../models/instructor');
router.get('/signup', function(req, res, next) {
res.render('users/signup');
});
router.get('/login', function(req, res, next){
res.render('users/login')
});
//Registering a user
router.post('/signup', function(req, res, next){
var first_name = req.body.first_name;
var last_name = req.body.last_name;
var email = req.body.email;
var password = req.body.password;
var password2 = req.body.password2;
var type = req.body.type;
req.checkBody('first_name', 'First name is required.').notEmpty();
req.checkBody('first_name', 'Please enter a shorter first name.').len(1, 40);
req.checkBody('last_name', 'Last name is required.').notEmpty();
req.checkBody('last_name', 'Please enter a shorter last name.').len(1, 40);
req.checkBody('email', 'Email is required.').notEmpty();
req.checkBody('email', 'Email must be valid.').isEmail();
req.checkBody('email', 'Please enter a shorter email.').len(1, 40);
req.checkBody('password', 'Password is required.').notEmpty();
req.checkBody('password2', 'Passwords must match.').equals(req.body.password);
req.checkBody('password', 'Please choose a password between 6 to 50 characters.').len(6, 50);
var errors = req.validationErrors();
if(errors){
res.render('users/signup', {
errors: errors,
first_name: first_name,
last_name: last_name,
email: email,
password: password,
password2: password2
});
} else {
var newUser = new User({
email: email,
password: password,
type: type
});
var newStudent = new Student({
first_name: first_name,
last_name: last_name,
email: email,
});
var newInstructor = new Instructor({
first_name: first_name,
last_name: last_name,
email: email,
});
if(type == 'student'){
User.saveStudent(newUser, newStudent, function(err, user){
console.log('Student saved');
});
} else {
User.saveInstructor(newUser, newInstructor, function(err, user){
console.log('Instructor saved');
});
}
res.redirect('/classes');
}
});
passport.serializeUser(function(user, done){
done(null, user._id);
});
passport.deserializeUser(function(id, done){
User.getUserByEmail(function(err, user){
done(err, user);
});
});
//Login in a user
router.post('/login',passport.authenticate('local', {
failureRedirect:'/users/login',
failureFlash:'Wrong Username or Password'
}), function(req, res){
var usertype = req.user.type;
res.redirect('/classes');
});
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(email, password, done) {
User.getUserByEmail(email, function(err, user){
if (err) return done(err);
if(!user){
return done(null, false, { message: 'Unregistered email'});
}
if (!user.comparePassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
module.exports = router;
Clearly, it will give an undefined function error since comparePassword is not a function defined for User Schema. You can use it as User.comparePassword since it has the function (in the JS file), but the user (object of the user schema - mongo) has no such function defined.
Do this before you export the User,
userSchema.methods.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err) throw err;
callback(null, isMatch);
});
};
Hope it helps.
You have 'User' but you are using 'user'. Note the case sensitivity.
Use below code:
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(email, password, done) {
User.getUserByEmail(email, function(err, user){
if (err) return done(err);
if(!user){
return done(null, false, { message: 'Unregistered email'});
}
if (!User.comparePassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
Suggestion:
If you are using module.exports than you can export the entire block with it so you need not to write module.exports again and again like you have did.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcryptjs')
var userSchema = new Schema({
email: { type: String },
password: { type: String },
type: { type: String }
});
var User = mongoose.model('User', userSchema);
module.exports = model;
//Get a User by id
model.getUserById = function(id, callback){
User.findById(id, callback);
}
//Get a User by email
model.getUserByEmail = function(email, callback){
var query = {email : email}
User.findOne(query, callback);
}
//Save a student
model.saveStudent = function(newUser, newStudent, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash){
if (err) {throw err}
newUser.password = hash;
//Saves both a user and student
async.parallel([newUser.save, newStudent.save], callback);
})
})
}
//Save a instructor
model.saveInstructor = function(newUser, newInstructor, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash){
if (err) {throw err}
newUser.password = hash;
//Saves both a user and instructor
async.parallel([newUser.save, newInstructor.save], callback);
})
})
}
//Checks if password matches.
model.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err) throw err;
callback(null, isMatch);
});
}
model.schema = User;