I am new to node JS. I am working on authenticating users against backend MYSQL.
Here is the code snippet of authentication
function Authenticate(username, password, fn) {
connection.connect();
var user;
connection.query('SELECT * from Users where username = ' +
connection.escape(username) + ' and password =' + connection.escape(password),
function(err, rows) {
user = rows[0].username;
});
if (!user) {
return fn(new Error('cannot find user'));
} else {
return fn(null, user);
}
connection.end();
}
This is my call back function.
app.post('/Login', function(req, res) {
Authenticate(req.body.username, req.body.password, function(err, user) {
if (user) {
req.session.regenerate(function() {
req.session.user = user;
req.session.success = 'Authenticated as ' + user;
res.redirect('Home');
});
} else {
req.session.error = 'Authentication failed, please check your username and password.';
res.redirect('Login');
}
});
})
I am getting an error, which i cannot get my head around.
TypeError: Cannot set property 'error' of undefined
at /...../.../node_modules/app.js:42:23
at Authenticate (/..../..../node_modules/app.js:82:11).
Please share your thoughts!
Takes the else out and see if any other req.session functions properly if not check if middleware is configured correctly for express validator
Related
I am currently working on a "Basic Authetntication" for Node JS. It should accept requests like the following:
POST http://localhost:8080/authenticate/
Authorization: Basic YWRtaW46MTIz
The AuthenticationService.js first reads the header and then passes the whole thing to the Userservice.js
AuthenticationService.js
async function basicAuth(req, res, next) {
// make authenticate path public
if (req.path === '/') {
return next();
}
if (!req.headers.authorization || req.headers.authorization.indexOf('Basic ') === -1) {
return res.status(401).json({ message: 'Missing Authorization Header' });
}
// verify auth credentials
const base64Credentials = req.headers.authorization.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
console.log("AuthenticationService "+username+" "+password);
const user = await userService.authenticate({ username, password });
if (!user) {
return res.status(401).json({ message: 'Invalid Authentication Credentials' });
}
req.user=user
res.send(user)
next();
}
module.exports = {
basicAuth
}
The user service checks if the user is found and checks if the password is valid, only then the user object is sent back to the authentication service.
UserService.js
async function authenticate({ username, password }) {
let user = await User.findOne({userID: username})
user.comparePassword(password.toString(), function(err,isMatch) {
if (err){
console.log("error")
throw err;
}
if(isMatch)
{
console.log("Password correct")
}
if(!isMatch){
console.log("Password wrong")
}});
if(user){
return user;
}
else{
return null;
}
}
module.exports = {
authenticate
}
The .comparePassword-Method is inside the Usermodel.js:
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
const User = mongoose.model("User", UserSchema);
module.exports = User;
How can I send the boolean value of isMatch in the Userservice.js outside it's scope, so I can send the userobject back to the AuthenticationService.js depending on the correct password ? How can I improve that code ?
I erase the authenticate-method in Userservice.js and just call the crud-method. After that I call the compare-method and inside the if/else-block I pass a res.send.
function basicAuth(req, res, next) {
if (!req.headers.authorization || req.headers.authorization.indexOf('Basic ') === -1) {
return res.status(401).json({
message: 'Missing Authorization Header'
});
}
// verify auth credentials
const base64Credentials = req.headers.authorization.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
console.log("AuthenticationService " + username + " " + password);
userService.findUserById(username, function(error, user) {
user.comparePassword(password.toString(), function(err, isMatch) {
if (err) {
console.log("Fehler")
throw err;
}
/*Passwort richtig*/
if (isMatch) {
res.send(user);
}
/*Passwort falsch*/
if (!isMatch) {
res.status(401).json({
message: 'Passwort und userID stimmen nicht überein.'
});
}
});
})
}
I am new to StackOverflow, and to the development world. Currently learning JS and node, I am developing a personal project which will be a task management web app. I wrote the register/auth controllers for user data inserts/checks in DB (using MySQL), but ATM I am saving the password in plain text. I want to hash the password and save it in the DB, but when I go look into the table, the passed value is saved as "Object Promise", so it's not currently hashing I think. How can I correctly save the value in registration and validate it in auth? Below is the code of both auth and register controllers. Thanks.
register-controller:
var mysqlConnection = require ('../config');
const bcrypt = require ('bcrypt');
const saltRounds = 10;
module.exports.register=function(req,res){
var today = new Date();
var users={
"firstname":req.body.firstname,
"lastname" : req.body.lastname,
"email":req.body.email,
"password":bcrypt.hash(req.body.password, saltRounds),
"signup_date":today,
"last_login_date":today
}
mysqlConnection.query('SELECT count(email) as count FROM users where email = "' + req.body.email + '"', function (error, results) {
console.log(error, results[0].email);
})
mysqlConnection.query('INSERT INTO users SET ?',users, function (error, results, fields) {
console.log(error, results);
if (error) {
res.json(
error
)
}else{
console.log('User registered succesfully.');
res.redirect('/');
}
});
}
and this is auth-controller:
var mysqlConnection = require ('../config');
const bcrypt = require ('bcrypt');
module.exports.auth = function (req, res, next) {
var email = req.body.email
var password = req.body.password
console.log(email, password);
mysqlConnection.query('SELECT password FROM users where email = "' + email + '"', function (error, results) {
console.log(error, results[0]);
if (error) {
res.error = error;
}else{
if(results.length >0){
bcrypt.compare(password,results[0].password, function (err,res){
if(password === results[0].password){
console.log('User logged in succesfully.');
res.error = error;
res.user = results[0];
res.redirect('/');
}else{
res.error = error;
res.user = null;
}
}
)}
else{
res.error = error;
res.user = null;
res.redirect('/register');
}
}
next();
});
}
I am trying to build a registration page with nodeJS and firebase.
When the user gets a registration error the page reloads and the error is shown to the user.
Then if the user tries to register, he gets to the desired page but I get:
Error: Can't set headers after they are sent.
After several hours of researching, I think I have understood the problem.
My code is probably already in the Body or Finished state, but some function tried to set a header or statusCode
With this knowledge, I tried to solve this error but I don't get it done.
Here is my user.js(controller) code:
var express = require('express');
var firebase = require('firebase');
var router = express.Router();
var User = require('../models/user');
var errors;
var errorMessage;
/**
sign up
*/
//sign up page route
router.get('/', function (req, res, next) {
console.log(errors);
if (errors) {
//Handle the errors and show them to the user
res.render('signUp', {error: true, errorMessage: errorMessage});
}else {
res.render('signUp', {title: 'Sign up', user: false, login: true});
}
});
// sign up request
router.post('/', function(req, res, next){
console.log(req.body.user.email + ' made a registration request');
console.log('Passwword: ' + req.body.user.password);
var email = req.body.user.email;
var password = req.body.user.password;
//reference to the firebase database
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
if (error) {
console.log(error.code);
console.log(error.message);
errorMessage = error.message;
errors = true;
res.redirect('/');
}
});
//if user is logged in redirect to homepage
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
res.redirect('/users/home');
console.log('User: ' + user.email + ' has logged in');
}
});
});
module.exports = router;
I hope someone can help me.
If you are using version 7+ of node, you can use async/await like I did in the following snippet:
var express = require('express');
var firebase = require('firebase');
var router = express.Router();
var User = require('../models/user');
var errors;
var errorMessage;
async function createUser(email, password) {
return new Promise(resolve => {
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
if (error) {
console.log(error.code);
console.log(error.message);
errorMessage = error.message;
errors = true;
return resolve(true)
}
resolve(false)
});
})
}
async function authChange() {
return new Promise(resolve => {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
console.log('User: ' + user.email + ' has logged in');
return resolve(true)
}
resolve(false)
});
})
}
// sign up request
router.post('/', async function(req, res, next) {
console.log(req.body.user.email + ' made a registration request');
console.log('Passwword: ' + req.body.user.password);
var email = req.body.user.email;
var password = req.body.user.password;
//reference to the firebase database
let error = await createUser(email, password)
if (error) {
res.redirect('/');
} else {
let logged = await authChange()
if (logged) {
res.redirect('/users/home');
}
}
});
module.exports = router;
I've just started with meanjs. When I've taken a look at it server side module user profile controller, I find that mongoose model User is available in req object.
From where it has got added in req object?
Refer the code below, I wants to understand var user = req.user;, How user is added in req object?
'use strict';
/**
* Module dependencies.
*/
var _ = require('lodash'),
errorHandler = require('../errors.server.controller.js'),
mongoose = require('mongoose'),
passport = require('passport'),
User = mongoose.model('User');
/**
* Update user details
*/
exports.update = function(req, res) {
// Init Variables
var user = req.user;
var message = null;
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
if (user) {
// Merge existing user
user = _.extend(user, req.body);
user.updated = Date.now();
user.displayName = user.firstName + ' ' + user.lastName;
user.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
});
} else {
res.status(400).send({
message: 'User is not signed in'
});
}
};
/**
* Send User
*/
exports.me = function(req, res) {
res.json(req.user || null);
};
In meanjs app.param([name], callback) is used, whenever a route with some id like articeId in parameter is accessed, app.param([name], callback) middleware is triggered. In meanjs it sets req.article like this.
app.param('articleId', articles.articleByID);
and in articleByID
exports.articleByID = function(req, res, next, id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(400).send({
message: 'Article is invalid'
});
}
Article.findById(id).populate('user', 'displayName').exec(function(err, article) {
if (err) return next(err);
if (!article) {
return res.status(404).send({
message: errorHandler.getErrorMessage(err)
});
}
req.article = article;
next();
});
};
more on app.param see http://expressjs.com/api.html#app.param
Passport’s authentication middleware sets req.user upon successful login.
See http://passportjs.org/guide/authenticate/.
I just looking for solution which makes verification email with token for my local autentification in passport.js
Is there some plugin or component for node which can make me verification easyer? Or I have to do it myself?
My controller
exports.postSignup = function(req, res, next) {
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password must be at least 4 characters long').len(4);
req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);
var errors = req.validationErrors();
if (errors) {
req.flash('errors', errors);
return res.redirect('/signup');
}
var user = User.build({
email: req.body.email,
password: req.body.password,
});
User
.find({ where: { email: req.body.email } })
.then(function(existingUser){
if (existingUser) {
req.flash('errors', { msg: 'Account with that email address already exists.' });
return res.redirect('/signup');
}
user
.save()
.complete(function(err){
if (err) return next(err);
req.logIn(user, function(err){
if (err) return next(err);
res.redirect('/');
});
});
}).catch(function(err){
return next(err);
});
};
Thanks for any opinion!
Implementing this yourself is pretty straightforward.
The pseudocode:
//A user registers
//User is stored along with a random token string and a variable set to false
//User is sent a verification email
//Verification email has a link with the random token and a unique ID for that user
//Link goes to a route that takes the token as a parameter
//Match the user and the random token
//If they match - change a variable to verified
The package I use to generage the random string is:
https://www.npmjs.com/package/randomstring
Local signup strategy
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function (req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function () {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({'local.email': email}, function (err, user) {
// if there are any errors, return the error
if (err) {
return done(err);
}
// check to see if theres already a user with that email
if (user) {
console.log('that email exists');
return done(null, false, req.flash('signupMessage', email + ' is already in use. '));
} else {
User.findOne({'local.username': req.body.username}, function (err, user) {
if (user) {
console.log('That username exists');
return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
}
if (req.body.password != req.body.confirm_password) {
console.log('Passwords do not match');
return done(null, false, req.flash('signupMessage', 'Your passwords do not match'));
}
else {
// create the user
var newUser = new User();
var permalink = req.body.username.toLowerCase().replace(' ', '').replace(/[^\w\s]/gi, '').trim();
var verification_token = randomstring.generate({
length: 64
});
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.local.permalink = permalink;
//Verified will get turned to true when they verify email address
newUser.local.verified = false;
newUser.local.verify_token = verification_token;
try {
newUser.save(function (err) {
if (err) {
throw err;
} else {
VerifyEmail.sendverification(email, verification_token, permalink);
return done(null, newUser);
}
});
} catch (err) {
}
}
});
}
});
});
}));
I use a combination of /permalink/random-token for the verification URL
The route should look like this:
app.get('/verify/:permaink/:token', function (req, res) {
var permalink = req.params.permaink;
var token = req.params.token;
User.findOne({'local.permalink': permalink}, function (err, user) {
if (user.local.verify_token == token) {
console.log('that token is correct! Verify the user');
User.findOneAndUpdate({'local.permalink': permalink}, {'local.verified': true}, function (err, resp) {
console.log('The user has been verified!');
});
res.redirect('/login');
} else {
console.log('The token is wrong! Reject the user. token should be: ' + user.local.verify_token);
}
});
});