I'm implementing a password reset following a tutorial but running into a problem. My req.body.email is coming back undefined. I have body-parser installed and my other routes are running perfectly.
Here is my code summary:
var express = require('express');
var router = express.Router({ mergeParams: true });
var Kids = require('../models/kid');
var User = require('../models/user');
var async = require('async');
var nodemailer = require('nodemailer');
var crypto = require('crypto');
var middleware = require('../middleware');
router.post('/password_reset', function(req, res, next) {
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
console.log(req.body.email); <====== Returning and undefined
console.log(user); <====== Returning as null
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/password_reset');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
}
});
and my form
<form action="/password_reset" method="POST" >
<div class="form-group">
<label for="exampleInputEmail1">Enter your email address</label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp" placeholder="Enter email" required>
</div>
<button type="submit" class="btn btn-warning">Submit</button>
</form>
You have two problems:
You aren't submitting any data
Your <input> has no name attribute, so it can't be a successful control.
If you want req.body.email to have data in it then you need to say name="email".
Related to this, you said <label for="exampleInputEmail1"> but id="email". The for attribute needs to match the id of the element it is labelling. Then aria-describedby="emailHelp" needs to match the ID of the element that is labelling the current element … and isn't needed when you have a real <label>.
You aren't parsing the submitted data
See the documentation for req.body:
Contains key-value pairs of data submitted in the request body. By default, it is undefined, and is populated when you use body-parsing middleware such as express.json() or express.urlencoded().
You haven't used any body-parsing middleware.
Your form is submitting urlencoded data (the default) so use express.urlencoded():
router.use(express.urlencoded())
Related
This question already has answers here:
How to access POST form fields in Express
(24 answers)
Closed 2 years ago.
I have a simple form:
<form method="POST">
<div class="form-group">
<label>Email address</label>
<input type="email" name="email" class="form-control" />
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
and I have a simple model:
const User = mongoose.model('User', {
email: {
type: String,
},
password: {
type: String,
}
});
and a simple post method
.post(async (req, res) => {
console.log(req.body);
const user = new User(req.body);
try {
const saveUser = await user.save();
res.send(saveUser);
} catch (error) {
res.send(error);
}
}
And yet, when i submit my form at the HTML file i get back an empty object.. i've tried every single one of SO solutions and none of them work for me.
NOTE: that i am using a JSON parser: app.use(express.json());.
please help ?
Your form is not sending JSON encoded data. Instead it uses application/x-www-form-urlencoded. Longer read Therefore you either need a bodyParser or you send the form data JSON encoded.
Try converting the user instance to a JSON string: res.send(saveUser.toJSON());
Make sure you have body-parser installed and imported to your project. npm i body-parser
const bodyParser = require("body-parser")
app.use(bodyParser.urlencoded({ extended: true }));
This is the method I am familiar when it comes to create a new entry
let email = req.body.email
let password = req.body.password
let user = {email: email, password: password}
User.create(user, (err, newUser) => {
if(err) // handle err
else // do something - redirect, etc..
})
Solved:
app.use(express.urlencoded({
extended: true
}));
I am trying to get the token value from the following URL http://localhost:3000/users/reset/e3b40d3e3550b35bc916a361d8487aefa30147c8. I have a get request that checks if the token is valid and redirects the user to a reset password screen. I also have a post request but when I console req.params.token, it outputs :token instead of e3b40d3e3550b35bc916a361d8487aefa30147c8. I am wondering if the form action is correct but don't know how to get the token value from it.
Reset Password Get Request
router.get('/reset/:token', (req, res) => {
console.log(req.params.token) // e3b40d3e3550b35bc916a361d8487aefa30147c8
User.findOne({
resetPasswordToken: req.params.token,
resetPasswordExpires: {
$gt: Date.now()
}
}, (err, user) => {
if (!user) {
req.flash('error_msg', 'The password reset token is invalid or has expired.')
return res.redirect('/users/forgot')
}
res.render('reset')
})
})
reset.ejs
<% include ./partials/messages %>
<form action="/users/reset/:token" method="POST">
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Please enter a password."
value="<%= typeof password != 'undefined' ? password : '' %>" />
</div>
<button type="submit" class="btn btn-primary btn-block">Register</button>
</form>
Reset Password Post Request
router.post('/reset/:token', (req, res) => {
console.log(req.params.token) // :token
User.findOne({
resetPasswordToken: req.params.token,
resetPasswordExpires: {
$gt: Date.now()
}
}, (err, user) => {
if (!user) {
req.flash('error_msg', 'The password reset token is invalid or has expired.')
return res.redirect('/users/forgot')
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function (err) {
req.flash('success_msg', 'Working.')
return res.redirect('/users/login')
})
})
})
In your form in your HTML, you have this:
<form action="/users/reset/:token" method="POST">
That's going to make the actual URL that gets requested when the form is posted be:
/users/reset/:token
There's no code doing any substitution for the :token here. That's just getting sent directly to the server as the URL.
So, when you then have:
router.post('/reset/:token', (req, res) => {
console.log(req.url); // "/user/reset/:token"
console.log(req.params.token); // ":token"
});
What req.params.token is showing you is whatever is in the URL that's after /users/reset. In your case, that is the literal string ":token". For req.params.token to actually have to token in it, you would have to insert the actual token into the URL so your form tag looks like this:
<form action="/users/reset/e3b40d3e3550b35bc916a361d8487aefa30147c8" method="POST">
Or, you will have to get access to the token some other way such as from the express session, from a cookie, from a field in the form, etc...
To get a URL parameter's value
app.get('/reset/:token', function(req, res) {
res.send("token is " + req.params.token);
});
To get a query parameter ?token=Adhgd5645
app.get('/reset/?token=Adhgd5645', function(req, res) {
res.send("token is " + req.query.token);
});
I am trying to adapt some code taken from:
https://github.com/expressjs/express/blob/master/examples/auth/index.js
and incorporate into a login form. The issue is that when running the code and selecting the login button the following is logged in the console:
POST /login
Authenticating undefined:foobar
Authentication failed, please check your username and password. (use "tj" and "foobar")
I'm unsure as to why the user is being returned as undefined when I am inputting tj and foobar as the login and password.
HTML:
<div class="login">
<form method="post" action="/login">
<p><input type="text" name="login" value="" placeholder="Username"></p>
<p><input type="password" name="password" value="" placeholder="Password"></p>
<p class="remember_me">
<label>
<input type="checkbox" name="remember_me" id="remember_me">
Remember me on this computer
</label>
</p>
<p class="submit"><input type="submit" name="commit" value="Login"></p>
</form>
</div>
<div class="login-help">
<p>Forgot your password? Click here to reset it.</p>
</div>
JS:
/**
* Module dependencies.
*/
var express = require('express');
var hash = require('./pass').hash;
var bodyParser = require('body-parser');
var session = require('client-sessions');
var app = module.exports = express();
// dummy database
var users = {
tj: { name: 'tj' }
};
// when you create a user, generate a salt
// and hash the password ('foobar' is the pass here)
hash('foobar', function (err, salt, hash){
if (err) throw err;
// store the salt & hash in the "db"
users.tj.salt = salt;
users.tj.hash = hash;
});
// check if user is logged in, if not redirect them to the index
function requireLogin (req, res, next) {
if (!req.user) {
res.redirect('/');
} else {
next();
}
};
// Authenticate using our plain-object database
function authenticate(name, pass, fn) {
if (!module.parent) console.log('Authenticating %s:%s', name, pass);
var user = users[name];
// query the db for the given username
if (!user) return fn(new Error('cannot find user'));
// apply the same algorithm to the POSTed password, applying
// the hash against the pass / salt, if there is a match we
// found the user
hash(pass, user.salt, function(err, hash){
if (err) return fn(err);
if (hash == user.hash) return fn(null, user);
fn(new Error('invalid password'));
});
}
app.post('/login', function (req, res){
console.log("POST /login")
authenticate(req.body.username, req.body.password, function(err, user){
if (user) {
// Regenerate session when signing in
// to prevent fixation
req.session.regenerate(function(){
// Store the user's primary key
// in the session store to be retrieved,
// or in this case the entire user object
req.session.user = user;
/*req.session.success = 'Authenticated as ' + user.name
+ ' click to logout. '
+ ' You may now access /restricted.';*/
res.redirect('/queryInterface.html');
});
} else {
console.log('Authentication failed, please check your '
+ ' username and password.'
+ ' (use "tj" and "foobar")');
res.redirect('/');
}
});
});
You are seeing the user as undefined because you are using req.body to access an undefined input field.
You are authenticating with req.body.username, but your input field has the name login.
req.body is populated with the names of your input fields. Your input should look like this when trying to access the username by req.body.username.
<input type="text" name="username" value="" placeholder="Username">
I need your help. I want to make User registration form and use Nodejs, Express.js, MongoDB(mongoose) and give me very simple example how to make user registration form with: Name, Email, Password and Mobile Number :) I've made mongoose schema and give values like that Name: req.body.name but it won't work :/ In my oppinion I made something bad.
this is my code and if you think it's not correct, please correct it. (sorry for my bad english). this is server.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/addressbookdb');
var express = require('express');
var app = express();
var db = mongoose.connection;
app.use(express.static(__dirname + '/../client'));
app.post("/",function(req,res){
res.end("Registration Succesfully Completed!");
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
console.log("connected.")
});
// Schema
var RegSchema = mongoose.Schema({
Name: String,
Email: String,
Pass: String,
Num: Number,
reg_time : {
type : Date, default: Date.now
}
}, { collection: 'AddressCol' });
// Model
var UserReg = mongoose.model('UserReg', RegSchema);
// Add in collection
var UserAdd = new UserReg({
Name: req.body.name,
Email: req.body.email,
Pass: req.body.pass,
Num: req.body.num,
});
// Save
UserAdd.save(function (err, fluffy) {
if (err) return console.error(err);
});
});
app.listen(8000, function() {
console.log("Server is running!");
});
and this is my HTML page:
<div class="form-group">
<input type="text" class="form-control" id="name" placeholder="name><br>
<input type="email" class="form-control" id="email" placeholder="Email"><br>
<input type="password" class="form-control" id="pass" placeholder="Password"><br>
<input type="number" class="form-control" id="num" placeholder="Number"><br>
<button type="submit" class="btn btn-primary" id="reg-form-btn">Registration!</button>
</div>
<script>
$(document).ready(function() {
$("#reg-form-btn").click(function() {
var name = $("#name").val();
var email = $("#email").val();
var pass = $("#pass").val();
var num = $("#num").val();
$.post("/", {
Name: name,
Email: email,
Pass: pass,
Num: num
});
});
});
</script>
Maybe you should consider Passport or another module.
But you can do something like this:
app.post('/signup', function (req, res, next) {
var user = {
Name: req.body.name,
Email: req.body.email,
Pass: req.body.pass,
Num: req.body.num
};
var UserReg = mongoose.model('UserReg', RegSchema);
UserReg.create(user, function(err, newUser) {
if(err) return next(err);
req.session.user = email;
return res.send('Logged In!');
});
});
app.post('/login', function (req, res, next) {
var email = req.body.email;
var pass = req.body.pass;
User.findOne({Email: email, Pass: pass}, function(err, user) {
if(err) return next(err);
if(!user) return res.send('Not logged in!');
req.session.user = email;
return res.send('Logged In!);
});
});
app.get('/logout', function (req, res) {
req.session.user = null;
});
Then you should have a middleware to handle authentication
function isLoggedIn (req, res, next) {
if (!(req.session && req.session.user)) {
return res.send('Not logged in!');
}
next();
}
And use it on the private routes
app.get("/api", isLoggedIn, function (req, res) {
//Something private
})
Here is a nice tutorial how to make what you want using very useful module passport. Also you will have a quick look at Jade template engine which can be useful in your further learning of creating express apps.
check this tutorial...you can ignore Angular and mongojs if you want:
http://www.phloxblog.in/single-page-application-angular-js-node-js-mongodb-mongojs-module/#.Vc20OXW1Gkq
You are missing body-parser. Try this in your server code:
const bodyParser = require('body-parser');
app.use(bodyParser);
Please refer the question How to access the request body when POSTing using Node.js and Express?
I'm learning Node.js and all its functionalities and I'm using scotch's tutorial (https://scotch.io/tutorials/easy-node-authentication-setup-and-local), I built what he proposed and it was really good, but then I wanted to get more informations for user, like name and a special number called SIAPE as my user model code shows: user.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var userSchema = mongoose.Schema({
local : {
name : String,
email : String,
password : String,
siape : String
}
});
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8),null);
};
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
module.exports = mongoose.model('User', userSchema);
And then set up my passport.js to update those thing to my mangodb database with mongoose, but it dosen't work and I dont know why.
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var User = require('../app/models/users');
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'siape',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, siape,password, email,name, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
console.log('USERNAME:' + name );
console.log('EMAIL:' + email );
console.log('PASSWORD:' + password );
console.log('SIAPE:' + siape );
console.log('DONE:' + done);
console.log('REQ:' + req);
// 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.siape' : siape }, 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) {
return done(null, false, req.flash('signupMessage', 'Email já existe'));
} else {
// if there is no user with that Email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.name = name;
newUser.local.email = email;
//newUser.local.password = newUser.generateHash(password);
newUser.local.password = password;
newUser.local.siape = siape;
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
passport.use('local-login', 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) { // callback with email and password from our form
// 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 before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
return done(null, user);
});
}));
};
Don't know if it helps, but I'll update also the html form:
<!-- views/signup.ejs -->
<!doctype html>
<html>
<head>
<title>Cadastro de professor</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <!-- load bootstrap css -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
<style>
body { padding-top:80px; }
</style>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span> Cadastro De Professor</h1>
<!-- show any messages that come back with authentication -->
<% if (message.length > 0) { %>
<div class="alert alert-danger"><%= message %></div>
<% } %>
<!-- LOGIN FORM -->
<form action="/signup" method="post">
<div class="form-group">
<label>Nome</label>
<input type="text" class="form-control" name="username">
</div>
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email">
</div>
<div class="form-group">
<label>Senha</label>
<input type="password" class="form-control" name="password">
</div>
<div class="form-group">
<label>SIAPE</label>
<input type="text" class="form-control" name="siape">
</div>
<button type="submit" class="btn btn-warning btn-lg">Cadastrar Professor</button>
</form>
<hr>
<p>Professor ja cadastrado?? Entre</p>
<p>Ou volte.</p>
</div>
</div>
</body>
</html>
A lot of things are happening that I don't quite understand, for example, I've put a console.log to print all the information sent in the html form, and this was what was print:
USERNAME:undefined
EMAIL:function verified(err, user, info) {
if (err) { return self.error(err); }
if (!user) { return self.fail(info); }
self.success(user, info);
}
PASSWORD:senha
SIAPE:SIAPE
DONE:undefined
REQ:[object Object]
And for the last part, the error printed in my terminal server:
/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/lib/utils.js:413
throw err;
^
TypeError: undefined is not a function
at Promise.<anonymous> (/home/aluno/28882/naest/AdmnistrationModule/config/passport.js:83:31)
at Promise.<anonymous> (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mpromise/lib/promise.js:177:8)
at Promise.emit (events.js:98:17)
at Promise.emit (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mpromise/lib/promise.js:84:38)
at Promise.fulfill (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mpromise/lib/promise.js:97:20)
at handleSave (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/lib/model.js:133:13)
at /home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/lib/utils.js:408:16
at /home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection/core.js:128:9
at /home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1197:7
at /home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1905:9
at Server.Base._callHandler (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:453:41)
at /home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:488:18
at MongoReply.parseBody (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:68:5)
at null.<anonymous> (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:446:20)
at emit (events.js:95:17)
at null.<anonymous> (/home/aluno/28882/naest/AdmnistrationModule/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:207:13)
aluno#lab2208-pc32:~/28882/naest/AdmnistrationModule$ clear
Just solved my problem, the problem was that local-signup only accepts 2 parameters as default, username and password for authentication, other variable are to be catched using the "req.body" prefix. This link helped me a lot
Does passportjs LocalStrategy allow more parameters than the default username and password?