Flash message in node js - node.js

I want a login page where the user enters their username and password, if it match then login is successful otherwise I want to show the flash message.
I've tried many different ways of doing this but couldn't find the correct way.
router.get('/login', function (req, res) {
res.render('login', {
layout: 'layouts/main/subpages',
topimagetype: 'home',
title: 'Log In',
message: req.flash('loginMessage')
});
});

You use the connect flash which is really simple to use.
Install the connect-flash via npm.
Here i give you example might be its works for you.
index.js // Router
router.get('/login', function (req, res) {
res.render('login', {
layout: 'layouts/main/subpages',
topimagetype: 'home',
title: 'Log In',
message: req.flash('loginMessage')
});
});
Passport.js // Configuration file
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function (req, email, password, done) {
pool.getConnection(function (err, connection) {
connection.query("SELECT * FROM user WHERE user_name = '" + email + "'", function (err, rows) {
if (err)
return done(err);
if (!rows.length) {
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (!(passwordHash.verify(password, rows[0].password)))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
var userType={};
userType.super=false;
userType.admin=false;
userType.normal=false;
if (rows[0].Roll_id == 1) {
userType.super=true;
} else if (rows[0].Roll_id == 2) {
userType.admin=true;
}
else {
userType.normal=true;
}
rows[0].type=userType;
rows[0].created_date = rows[0].created_date.toDateString();
return done(null, rows[0]);
});
});
}));
Html View
<div class="login">
<div class="login-screen">
<div class="container">
{{#message}}
<div style="margin-left: 35%; width: 30%;">
<div class="alert alert-danger">{{ message }}</div>
</div>
{{/message}}
<section class="main">
<form action="/login" method="post" role="form" class="form-1">
<p class="field">
<input type="text" name="email" placeholder="email" id="login-name">
<i class="icon-user icon-large"></i>
</p>
<p class="field">
<input type="password" name="password" placeholder="password" id="login-pass">
<i class="icon-lock icon-large"></i>
</p>
<p class="submit">
<button type="submit" name="submit"><i class="icon-arrow-right icon-large"></i></button>
</p>
</form>
</section>
</div>

Related

Form validation with flash messages in express js

I am trying to validate a form in express js before i post it onto the mongodb which i am using as a backend. My user.js for registration page looks something like this -
router.post('/register', (req, res) => {
userreg.register(
// eslint-disable-next-line new-cap
new userreg({
firstname: req.body.firstname,
lastname: req.body.lastname,
username: req.body.email,
usn: req.body.usn, // validate so that no space is taken or else request modal wont work
course: req.body.course,
}),
req.body.password,
(err) => {
if (err) {
console.log(err);
res.render('register', { user: 'error' });
} else {
console.log('no error');
res.render('submit-success', { username: req.body.firstname });
}
}
);
});
and my register.ejs looks something like this -
<form class="user" action = '/users/register' method="POST">
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<input type="text" class="form-control form-control-user" id="exampleFirstName" name="firstname" placeholder="First Name">
</div>
<div class="col-sm-6">
<input type="text" class="form-control form-control-user" id="exampleLastName" name="lastname" placeholder="Last Name">
</div>
</div>
<div class="form-group">
<input type="email" class="form-control form-control-user" id="exampleInputEmail" name="email" placeholder="Email Address">
</div>
<div class="form-group">
<input type="text" class="form-control form-control-user" id="exampleInputUSN" name="usn" placeholder="USN">
</div>
<div class="form-group">
<select class=" form-control selectpicker" name="course">
<optgroup label="Course"></optgroup>
<option selected hidden disabled>Course</option>
<option value="mca">Computer Applications</option>
<option value="mba">Business Administration</option>
</optgroup>
</select>
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="exampleInputPassword" name="password" placeholder="Password">
</div>
<div class="text-center">
<input type="submit" class = "btn btn-primary btn-user" value="Register">
</div>
</form>
By going through many sources on the internet(since i'm very very new to express js and im doing it as a part of my college project and since i can't consult any teachers for assistance during lockdown times) , I got to know that the validation part has to be implemented in user.js. Please help me with the code for validation and also displaying flash messages if field empty for atleast one field so that i can have a start atleast.
Thank you in advance
EDIT :
I Used the express-validator and ended up with the following changes -
var flash = require('connect-flash');
var app = express();
app.configure(function () {
app.use(express.cookieParser('keyboard cat'));
app.use(express.session({ cookie: { maxAge: 60000 } }));
app.use(flash());
});
app.get('/flash', function (req, res) {
// Set a flash message by passing the key, followed by the value, to
req.flash().
req.flash('info', 'There is an Error!')
res.redirect('/');
});
app.get('/', function (req, res) {
// Get an array of flash messages by passing the key to req.flash()
res.render('index', { messages: req.flash('info') });
});
const { check, validationResult } = require('express-validator');
router.post('/register', [
check('firstname', 'Please enter your first
name').exists().trim().escape().not().isEmpty(),
check('lastname', 'Please enter your last
name').exists().trim().not().isEmpty(),
check('username', 'Please enter an
email').exists().trim().not().isEmpty(),
check('usn', 'Please enter USN').exists().trim().not().isEmpty(),
check('course', 'Please enter Course').exists().trim().not().isEmpty(),
check('password', 'Please enter
password').exists().trim().not().isEmpty(),
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
req.flash('message', `${errors}`);
res.redirect('/users/register');
} else {
userreg.register(
// eslint-disable-next-line new-cap
new userreg({
firstname: req.body.firstname,
lastname: req.body.lastname,
username: req.body.email,
usn: req.body.usn, // validate so that no space is taken or else
request modal wont work
course: req.body.course,
})),
res.render('submit-success', { username: req.body.firstname });
}
}
);
And as a result , the if (!errors.isEmpty()) is being invoked but there is no flash message being displayed. Am i missing something else ?
I am assuming you are using connect-flash.
const { check, validationResult } = require('express-validator');
router.post('/register', [
check('firstname', 'Please enter your first name').exists().trim().escape().not().isEmpty(),
check('lastname', 'Please enter your last name').exists().trim().not().isEmpty(),
check('email', 'Please enter an email').exists().trim().not().isEmpty(),
// ...
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
req.flash('message', `${errors}`);
res.redirect('register');
}
else {
// your code here!
}
});
You might want to consider creating middleware to handle validation errors, to make your code cleaner.

ReactJs and Passport Auth

m trying to make auth system with react and Passport js
My passport look like this:
let passport = require('passport');
let User = require('../models/user');
let localStorage = require('passport-local').Strategy;
passport.serializeUser(function(user, done){
done(null, user.id)
});
passport.deserializeUser(function(id, done){
User.findById(id, (err, user) => {
done(err, user)
})
});
passport.use('local.signup', new localStorage({
usernameField: 'email', passwordField: 'password', passReqToCallback: true
}, function(req, email, password, done){
//Check valid
req.checkBody(req.body.email, 'Invalid email').notEmpty().isEmail();
req.checkBody(req.body.password, 'Invalid password').notEmpty().isLength({min: 4});
req.checkBody(req.body.name, 'Name is require!').notEmpty();
let errors = req.validationErrors(); //Get all errors for checkBody
if(errors){
let messages = [];
errors.forEach(function(error){
messages.push(error.msg)
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email': req.body.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= req.body.email;
newUser.password = newUser.encryptPassword(req.body.password);
newUser.name = req.body.name;
newUser.save((err, user) => {
if(err) return done(err);
return done(null, user);
})
})
}));
My route file:
const express = require('express');
const passport = require('passport');
let router = express.Router();
let User = require('../models/user');
router.post('/signup', passport.authenticate('local.signup', {
failureRedirect: '/', failureFlash: true
}), function(req, res,next){
console.log('Yes signUp');
});
module.exports = router;
React file:
handleChange = ev => {
this.setState({[ev.target.name]: ev.target.value});
}
onSubmit = ev => {
ev.preventDefault();
let user = {
name: this.state.name,
email: this.state.email,
password: this.state.password
}
axios.post('http://localhost:3001/signup', user)
.then(res=> { console.log(res) })
.catch(err=> { console.error(err) })
}
render() {
return (
<div className="container login-container">
<div className="title-login text-center">Login</div>
<hr/>
<div className="login-form">
<div className="form-group">
<input type="email" className="form-control" name="email" value={this.state.email} placeholder="Enter your Email.." onChange={this.handleChange} />
</div>
<div className="form-group">
<input type="text" className="form-control" name="name" value={this.state.name} placeholder="Enter your Name.." onChange={this.handleChange} />
</div>
<div className="form-group">
<input type="password" className="form-control" name="password" value={this.state.password} placeholder="Enter your password.." onChange={this.handleChange} />
</div>
<button className="btn btn-outline-primary btn-block" onClick={this.onSubmit}>Send</button>
</div>
</div>
)
}
The error is:
OPTIONS http://localhost:3001/ 404 (Not Found) signup:1 Failed to load
http://localhost:3001/: Response for preflight has invalid HTTP status
code 404. index.js:2178 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
Help!

Nodejs Passport authentication & local strategy not work through API Call

This is solved. Actually, the problem is with postman not on Passport code
I have a login system which is implemented through Nodejs Passport. For Login I use Handlebars for creating the UI and send the form data from frontend to backend.
These is my login Handlebars File
<form id="userloginform" method="post" action="/user/login">
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control" placeholder="Username or Email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control" placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
and on User.js file I have a code of authentication i.e like this
//Login Handler
passport.use('local-user', new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) {
console.log('error')
logger.log('error', 'Error Generates on User.getUserByUsername Query on users.js file');
throw err;
}
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) {
logger.log('error', 'Error Generates on User.comparePassword Query on users.js file');
throw err;
}
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Invalid Credential, please check carefully...!'})
}
});
});
}
));
//Login Authentication
router.post('/login',
passport.authenticate('local-user', {
failureRedirect: '/user/login',
badRequestMessage: 'Field cannot be blank.!!', //missing credentials
failureFlash: true
}),
function(req, res) {
console.log('hello');
req.flash('success_msg', 'Welcome ' + req.user.name);
req.flash('custom_msg', token);
//res.redirect('/success?username='+req.user.username);
res.redirect('/user/dashboard');
});
All these things are working pefectly.
Now when I call it through postman and pass two parameters i.e username and password then it does nothing. Simply failure redirect.
I have done this through proper nodejs with form submitted pattern. Now I want to be done through API from different Server.
Anyone have any idea then let me know. Any help is really appreciated.

Password confirmation with Passport

I've created a basic user registration form which works fine but I need to add a confirm password field.
My form is as follows:
<div class ="container form">
<div class="jumbotron form"><h2><i class="fa fa-user-plus" aria-hidden="true"></i> Signup</h2></div>
<form action = "/register" method="POST">
<div class="form-group">
<i class="fa fa-user" aria-hidden="true"></i>
<label for="username">Username</label>
<input type = "text" class = "form-control" placeholder = "Enter username" name="username">
</div>
<div class="form-group">
<i class="fa fa-key" aria-hidden="true"></i>
<label for="password">Password</label>
<input type = "password" class ="form-control" placeholder = "Enter password" name="password1">
</div>
<div class="form-group">
<i class="fa fa-key" aria-hidden="true"></i>
<label for="password">Confirm password</label>
<input type = "password" class ="form-control" placeholder = "Enter password" name = "password">
</div>
<div class="form-group">
<i class="fa fa-picture-o" aria-hidden="true"></i>
<label for="img">Image</label>
<input type = "text" class ="form-control" placeholder = "Enter image URL" name = "image">
</div>
<button type ="submit" class="btn btn-primary btn-lg">Signup</button>
</form>
</div>
So when a user hits submit, I obviously need the 2 password inputs to match and an error to be thrown if they don't.
I'm using Passport for authenitcation. I have the following setup:
// passport configuration
app.use(require("express-session")({
secret: "maidenJones",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(expressSanitizer());
app.use(function(req, res, next){
res.locals.currentUser = req.user;
res.locals.error = req.flash("error");
res.locals.success = req.flash("success");
next();
});
Register route:
router.post("/register", function(req, res){
var newUser = new User({username: req.body.username, image: req.body.image});
User.register(newUser, req.body.password, function(err, user){
if(err){
res.redirect("/blogs");
console.log(err);
}
passport.authenticate("local")(req, res, function(){
res.redirect("/blogs");
});
});
});
Not sure where to start to implement the password confirmation check
You have to move your registration logic inside the passport LocalStrategy and then use that strategy as a middleware in your routes.
Example:
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'passwd'
},
function(req, username, password, done) {
// User register logic
}
));
router.post('/register',
passport.authenticate('local', { failureRedirect: '/register' }),
function(req, res) {
res.redirect('/blogs');
});
more info here: passport-localstrategy
passport.use('local.signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function (req, email, password, done) {
//All validation logic comes here
let password1 = req.body.password;
let password2 = req.body.password2;
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Password must be more than 4 characters')
.not().isEmpty().isLength({ min: 4 });
let errors = req.validationErrors();
//just to see the output in your console
console.log(password1);
console.log(password2);
if (errors) {
let messages = [];
errors.forEach(function (error) {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
} else if (password1 !== password2) {
return done(null, false, req.flash('error', 'Password and Confirm Password must match'));
}
// You can then continue your code logic(submitting to database)

bcrypt.compareSync is always returning false

I verified that in my db I am saving the username and hash of the password. I am able to retrieve the name from the db, however when I check the password it always returns false. Not sure what is wrong.
Here is my HTML
<div ng-controller="userController">
<div class=user>
<form name="login_form">
<h2 class>Login</h2>
<h3 class = "login_page">UserName</h3>
<input ng-model="user" type="text" ng-minlength="1" required>
<h3 class = "login_page">Password</h3>
<input ng-model="password" type="password" name="password" ng-minlength="4" required>
<input type="submit" value="Login" ng-click="login()" >
<div ng-if ="login_form.$submitted" ng-messages="login_form.password.$error" style="color:maroon" role="alert">
<div ng-message="minlength">Your field is too short</div>
</div>
<p ng-if="error">Username or login is incorrect</p>
</form>
</div>
<div class=user>
<form name = "register_form">
<h2 class>Register</h2>
<h3 class = "login_page">UserName</h3>
<input ng-model="reg.name" type="text" required>
<h3 class = "login_page">Password</h3>
<input ng-model="reg.password" type="password">
<input type="submit" value="Register" ng-click="register()" required >
<div ng-if ="login_form.$submitted" ng-messages="login_form.password.$error" style="color:maroon" role="alert">
<div ng-message="minlength">Your field is too short</div>
</div>
<p ng-if="duplicate">That user name is taken, please choose another</p>
<p ng-if="correct">Registration Succesfull</p>
</form>
</div>
</div>
Here is my controller on the server side
var mongoose = require('mongoose'),
Todo = mongoose.model('Todo');
Login = mongoose.model('Login');
var bcrypt = require('bcrypt');
var name = ""
module.exports = (function(){
return {
save_name:function(req, res){
req.session.user = req.body.user
Login.findOne({name: req.body.user},
function(err, user) {
if(user){
console.log(user.password);
console.log( bcrypt.compareSync(req.body.password, user.password));
res.json({'error': false});
}else {
res.json({'error': true});
}
})
}, //end of save name method
register:function(req, res){
bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(8));
login = new Login({
name:req.body.user,
password: bcrypt.genSaltSync(8)
})
login.save(function(err){
if(err){
res.json({'error': true});
} else {
res.json({'sucess': true})
}
})
} // end of register user function
}
})();
You're saving a generated salt as the password instead of the actual hash itself. Also, explicitly calling genSalt*() is unnecessary. Lastly, you really should use the async functions instead, to avoid unnecessarily blocking the event loop. So with all of this in mind, you may end up with something like:
module.exports = {
save_name: function(req, res) {
req.session.user = req.body.user;
Login.findOne({ name: req.body.user },
function(err, user) {
if (err)
return res.json({ error: true });
bcrypt.compare(req.body.password,
user.password,
function(err, valid) {
res.json({ error: !!(err || !valid) });
});
});
}, // end of save name method
register: function(req, res) {
bcrypt.hash(req.body.password, 8, function(err, hash) {
if (err)
return res.json({ error: true });
login = new Login({
name: req.body.user,
password: hash
})
login.save(function(err) {
res.json({ error: !!err });
})
});
} // end of register user function
};
Despite other answers, if it is still not resolving your issue. Try by applying the toString() when passing the password upon login like this.
req.body.password.toString();
The immediate cause of your bug is in register you should be using bcrypt.hashSync(myPlaintextPassword, saltRounds) instead of genSaltSync. Fixing that should make things "work".
However, you need to recode all this to use the async bcrypt APIs or your application will respond very poorly under load (like crippled and unusable, not just "slow"). General rule: no sync calls in a node.js server.

Resources