I am trying to get some data from Mongoose using Express. I have created a username and password form to log in to my site. It is supposed to check the credentials and let them in if the credentials are the same as the ones stored on the database, but it is letting anything in (even if I put the wrong password). My source files seem fine, and the console is not throwing any errors. The Gists to the files are below:
login.ejs
register.ejs
And the app.js file (can't gist it due to my reputation):
var bodyParser = require('body-parser');
var express = require('express');
var mongoose = require('mongoose');
var app = express();
var options = {
server: {
socketOptions: {
keepAlive: 300000, connectTimeoutMS: 30000
}
},
replset: {
socketOptions: {
keepAlive: 300000,
connectTimeoutMS : 30000
}
}
};
var db = mongoose.connect('db_uri', options);
var Schema = mongoose.Schema;
var UserSchema = new Schema({
email: String,
password: String
});
var User = mongoose.model('Users', UserSchema);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname+'/public'));
app.set('view engine', 'ejs');
app.set('views', __dirname+'/public/templates');
app.get('/', function (req, res) {
res.render('index');
});
app.get('/registerPage', function (req, res) {
res.render('register') ;
});
app.get('/loginPage', function (req, res) {
res.render('login');
});
app.post('/register', function (req, res) {
var email = req.body.email;
var password = req.body.password;
var user = new User({
email: email,
password: password
});
user.save(function (err) {
if (err) throw err;
console.dir(user);
res.send('Account created successfully (email): ' + email);
});
});
app.post('/login', function (req, res) {
var email = req.body.email;
var password = req.body.password;
User.findOne( {email: email, password: password}, function (err) {
if (err) throw err;
res.render('portal');
});
});
app.listen(3000, function () {
console.log('Express server listening on http://localhost:3000');
});
Thanks for your help!
In the login handler, you're not actually checking if the query matches a user.
Perhaps you assume that err will be set in that case, but it won't be, because the query itself was performed successfully (it just didn't return any records).
You need to add an additional check to see if the query returned a valid user:
User.findOne( {email: email, password: password}, function (err, user) {
if (err) throw err;
if (! user) return res.send(401);
res.render('portal');
});
This will return a 401 ("Unauthorized") when the query didn't match a user.
Related
Good day, Please help me find the error in my code for level one authentication I could create a database, register users and store in their inputs using body parser, but I couldn't login already registered users. the login page keeps loading till it tells me a connection error, please help me out
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const app = express();
app.use(express.static("public"));
app.set('view-engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
mongoose.connect("mongodb://localhost:27017/User", {useNewUrlParser: true});
const userSchema = ({
email: String,
password: String
});
const User = new mongoose.model("User", userSchema);
const users = []
app.get("/", function(req, res){
res.render("first.ejs");
});
app.get("/login", function(req, res){
res.render("login.ejs");
});
app.get("/register", function(req, res){
res.render("register.ejs");
});
app.post("/register", function(req, res){
const newUser = new User({
email: req.body.username,
password: req.body.password
});
newUser.save(function(err){
if (err) {
console.log(err);
} else {
res.render("home.ejs");
}
});
});
app.post("/login", function(req, res){
const username = req.body.username;
const password = req.body.password;
User.findOne({email: username}, function(err, foundUser){
if (err) {
console.log(err);
} else {
if (foundUser) {
if (foundUser.password === password) {
res.send("hi");
}
}
}
});
});
app.listen(3000, function() {
console.log("Server started on port 3000.");
});
I am new to Node/mongodb/passport, trying to authenticate using passport.
here is my auth.js
var User = require('../models/userModel'),
passport = require('passport'),
BasicStrategy = require('passport-http').BasicStrategy,
jwt = require('jsonwebtoken');
passport.use(new BasicStrategy(function(userid, password, done){
User.findOne({ 'userid': 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);
})
}));
exports.generateToken = function(req, res, next){
req.token = jwt.sign({ id:req.user.userid },'secret key', { expiresInMinutes:120 });
next();
};
exports.respond = function(req, res){
req.status(200).json({
user: req.user,
token:req.token
});
};
exports.isAuthenticated = passport.authenticate('basic', {session:false});
For database, I simply created a user to test in the following way:
db.UserSchema.insert({"userid": "hm", "password":"mm123"})
here is my userModel.js
var mongoose = require('mongoose'),
bcrypt = require('bcrypt-nodejs');
var UserSchema = new mongoose.Schema({
userid: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
access_token: String
});
UserSchema.methods.verifyPassword = function(password, cb) {
bcrypt.compare(password, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', UserSchema);
when I send a request using postman and debug using node-inspector, user come as null in auth.js and in console
Runtime.getProperties failed.
Error: No scopes
here is the server.js
var express = require('express'),
mongoose = require('mongoose'),
bodyParser = require('body-parser'),
path = require('path'),
passport =require('passport'),
authentication = require('./auth/auth');
var db;
if (process.env.ENV == 'Test') {
db = mongoose.connect('mongodb://localhost/fxtest');
}else{
db = mongoose.connect('mongodb://localhost/fx');
}
var app = express();
var port = process.env.PORT || 3000;
app.listen(port, function(){
console.log('Running on Port using gulp:', port);
});
app.use(passport.initialize());
app.post('/auth',authentication.isAuthenticated,
authentication.generateToken, authentication.respond);
module.exports = app;
Can anyone give me any leads as to what am I missing here??
You're responding with the request object which you can't do. You need to respond on the response object.
Its also worth pointing out, that unless you have a cleanup procedure that needs to happen after you respond, you should use a return with your res object.
exports.respond = function(req, res){
// This is wrong
req.status(200).json({
user: req.user,
token:req.token
});
// This is correct
return res.status(200).json({
user: req.user,
token: req.token,
});
};
I got it resolved. The problem was I had given the collection name as UserSchema, whereas my model name was User. As stated in mongoose docs here:
Mongoose automatically looks for the plural version of your model
name
and so it was looking for users as a collection.
Preface: I'm new to node.js, express, socket.io and all of that. I realize my code is kinda messy and needs to be separated out into modules, etc -- but I've not done that yet because I was trying to get the authentication part working first. I have searched all over stackoverflow and other sites. I've found some promising examples, but I've just not been able to make it work.
I followed a couple of tutorials to create my express app which allows a user to register, login, and view their details. I also followed a tutorial which helped me make a basic socket.io chat. What I'm trying to do is combine them and have the user log in and then be redirected to the chat app. The problem I have is that when I redirect them, I have no way to know "who they are" on the socket.io side of things. Currently I've got it set up so you have to enter your name to chat -- I would like it to grab the info from the session and use that instead.
Currently when a user logs in, it does set a cookie (I can view it in the console). So I know the cookie is there. It also sets the info into the MongoStore. I've verified that as well with db.collection.find().
Here's the code that I have so far. If any of the experts out there could help me find a way to pass the session info over to socket.io, I would very much appreciate it!
var mongo = require('mongodb').MongoClient;
var bodyParser = require('body-parser');
var bcrypt = require('bcryptjs');
var csrf = require('csurf');
var path = require ('path');
var express = require('express');
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
var session = require('express-session');
var moment = require('moment');
var now = moment().format('L');
var http = require('http');
var MongoStore = require('connect-mongo')(session);
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
UserSchema = new Schema({
//id: ObjectId,
firstName: String,
lastName: String,
username: {
type: String,
unique: true,
uniqueCaseInsensitive:true
},
password: String,
email: {
type:String,
unique: true,
uniqueCaseInsensitive:true
},
accountType: String,
accountStatus: String,
acctActivation:{
type:String,
unique:true
},
joinDate: String
});
UserSchema.plugin(uniqueValidator,{ message: 'Error, {PATH} {VALUE} has already been registered.\r' });
var User = mongoose.model('User', UserSchema);
var app = express();
app.engine('ejs', require('ejs').renderFile);
app.locals.pretty = true;
//connect to mongo
mongoose.connect('mongodb://localhost/myUserDb');
//create server
var server = http.createServer(app).listen(3000);
var client = require('socket.io')(server);
console.log('listening on port 3000');
//middleware
app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended:true}));
app.use(session({
secret: 'mysecret!',
resave:false,
saveUninitialized: false,
stringify:true,
store: new MongoStore({
url: 'mongodb://127.0.0.1/sid2'
})
}));
app.use(csrf());
app.use(function(req,res,next){ // check to see if user already has a session, if so, query mongodb and update the user object
if(req.session && req.session.user){
User.findOne({email: req.session.user.email}, function(err, user){
if(user){
req.user = user;
delete req.user.password; // remove password field from session
req.session.user = req.user;
res.locals.user = req.user;
}
next();
});
}else{
next();
}
});
function requireLogin(req,res,next){ // check to see if user is logged in, if not, boot em
if(!req.user){
res.redirect('/login');
}else{
next();
}
};
function requireAdmin(req,res,next){ // check to see if accountType = Developer (or admin later) - if not, send them to dashboard
if(req.user.accountType !== 'Developer'){
res.redirect('/dashboard');
}else{
next();
}
};
app.get('/', function(req, res){
if(req.user){
res.render('dashboard.ejs');
}else{
res.render('index.ejs');
}
});
app.get('/register', function(req,res){
res.render('register.ejs', {csrfToken: req.csrfToken(),
error:false});
});
app.post('/register', function(req,res){
var hash = bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(10));
var user = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
username: req.body.username,
password: hash,
email: req.body.email,
accountType: 'Standard',
accountStatus: 'Active',
joinDate: now
});
user.save(function(err){
if(err){
console.log(err);
res.render('register.ejs', {csrfToken: req.csrfToken(),
error: err});
}else{
req.session.user = user;
res.redirect('/dashboard');
}
});
});
app.get('/login', function(req,res){
res.render('login.ejs', {
csrfToken: req.csrfToken(),error:false});
});
app.post('/login', function(req, res){
User.findOne({username: {$regex: new RegExp('^' + req.body.username, 'i')}}, function(err, user){
if(!user){
res.render('login.ejs', {error: 'Invalid username or password combination.',
csrfToken: req.csrfToken()});
}else{
if(bcrypt.compareSync(req.body.password, user.password)){
req.session.user = user;
res.redirect('/chat');
}else{
res.render('login.ejs', {error: 'Invalid username or password combination.',
csrfToken: req.csrfToken()});
}
}
});
});
app.get('/dashboard', requireLogin, function(req,res){
res.render('dashboard.ejs');
});
app.get('/chat', requireLogin, function(req,res){
res.render('chat.ejs');
});
app.get('/admin', requireLogin, requireAdmin, function(req,res){ //required logged in AND admin status
// var userlist = User.find({});
User.find({},{},function(err,docs){
res.render('admin.ejs',{ "userlist": docs
});
}) ;
// res.render('admin.ejs');
});
app.get('/logout', function(req,res){
req.session.reset();
res.redirect('/');
});
mongo.connect('mongodb://127.0.0.1/chat', function(err,db){
if(err) throw err;
client.on('connection', function(socket){
var col = db.collection('messages');
sendStatus = function(s){
socket.emit('status', s);
};
//emit all messages (shows old room data)
col.find().limit(100).sort({_id: 1}).toArray(function(err, res){
if(err) throw err;
socket.emit('output',res);
});
//wait for input
socket.on('input', function(data){
var name = data.name,
message = data.message,
whitespacePattern = /^\s*$/;
if(whitespacePattern.test(name) || whitespacePattern.test(message)){
sendStatus('Name and message is required.');
}else{
col.insert({name: name, message: message}, function(){
//emit latest message to all clients
client.emit('output', [data]);
sendStatus({
message: "Message sent",
clear: true
});
});
}
});
});
});
Ok, so I've finally figured it out. I used express-session to set the cookie, and then a module called express-socket.io-session to get it over to socket.io.
From there, I was able to use:
var data = socket.handshake.session;
console.log(data.user.username);
to retrieve the values I needed. All of these days searching and it was a very simple solution. I guess I just needed some sleep!
I'm using nodejs and MongoDB for the first time and I'm having trouble when I want to connect to the DB.
I read the quickstart from mongoosejs but it still doesn't work, here is my code (right now, all my code is only in one file) :
/***** Utilities *****/
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var path = require('path');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongo = require('mongodb');
var mongoose = require('mongoose');
app.listen(8080);
mongoose.connect('mongodb://localhost:8080/users');
var db = mongoose.connection;
db.on('error', function (error) {
console.log('/**************** ERROR **************\\');
console.log(error);
});
db.on('open', function () {
console.log("Hello World!");
});
var Schema = mongoose.Schema;
var UserSchema = new Schema({
pseudo: String,
password: String,
email: String
});
var Users = mongoose.model('users', UserSchema);
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.use(passport.initialize());
app.use(passport.session());
/***** Passport *****/
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
/***** Building routes *****/
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.post('/', function (req, res) {
var pseudo = req.body.pseudo;
console.log("/******************************\\") console.log(pseudo);
res.send('Hello ' + pseudo + '!');
});
app.get('/users', function (req, res) {
Users.find(function (error, users) {
if (error) console.log(error);
else res.render('users.jade', {
users: users
})
});
})
app.post('/create_user', function (req, res) {
var user = new Users({
pseudo: req.body.pseudo,
password: req.body.password,
email: req.body.email
});
user.save(function (error, user) {
if (error) console.log(error);
else res.render('create_user.jade');
});
});
app.get('/login', function (req, res) {
passport.authenticate('users', {
successRedirect: '/create_user',
failureRedirect: '/login',
}) res.render('login.jade
);
});
I'm trying to get data from the login page and store them into one mongo database but I'm when I start this file, mongo returns the following message:
MongoError: server localhost:8080 sockets closed
name: 'MongoError',
message: 'server localhost:8080 sockets closed'
I really don't know how to correct this error.
Where am I wrong? Is it because of a possible asynchronous problem?
The code
app.js:
var express = require('express');
var session = require('express-session');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoStore = require('connect-mongo')(session);
var mongoose = require('mongoose');
var passport = require('passport');
var config = require('./config');
var routes = require('./routes');
var mongodb = mongoose.connect(config.mongodb);
var app = express();
// view engine setup
app.set('views', config.root + '/views');
app.set('view engine', 'jade');
app.engine('html', require('ejs').renderFile);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(config.root + '/public'));
app.use(session({
name: 'myCookie',
secret: 'tehSecret',
resave: true,
saveUninitialized: true,
unset: 'destroy',
store: new mongoStore({
db: mongodb.connection.db,
collection: 'sessions'
})
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', routes);
app.set('port', config.port);
var server = app.listen(app.get('port'), function() {
if (config.debug) {
debug('Express server listening on port ' + server.address().port);
}
});
routes.js:
var express = require('express');
var router = express.Router();
var config = require('../config');
var userController = require('../controllers/user');
var authController = require('../controllers/auth');
router.get('/', function(req, res) {
res.render('index', {
title: config.app.name
});
});
router.route('/users')
.post(userController.postUsers)
.get(authController.isAuthenticated, userController.getUsers);
router.get('/signout', userController.signout);
module.exports = router;
models/user.js:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
}
});
// Execute before each user.save() call
UserSchema.pre('save', function(callback) {
var user = this;
// Break out if the password hasn't changed
if (!user.isModified('password')) return callback();
// Password changed so we need to hash it
bcrypt.genSalt(5, function(err, salt) {
if (err) return callback(err);
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return callback(err);
user.password = hash;
callback();
});
});
});
UserSchema.methods.verifyPassword = function(password, cb) {
bcrypt.compare(password, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
// Export the Mongoose model
module.exports = mongoose.model('User', UserSchema);
controllers/user.js:
var config = require('../config');
var User = require('../models/user');
exports.postUsers = function(req, res) {
if (config.debug)
console.log("user.postUsers()");
var user = new User({
username: req.body.username,
password: req.body.password
});
user.save(function(err) {
if (err)
return res.send(err);
if (config.debug)
console.log("saved");
res.json({
message: 'New user created!'
});
});
};
exports.getUsers = function(req, res) {
if (config.debug)
console.log("user.getUsers()");
User.find(function(err, users) {
if (err)
return res.send(err);
if (config.debug)
console.log("users", users);
res.json(users);
});
};
exports.signout = function(req, res) {
if (config.debug)
console.log("user.signout()");
res.clearCookie('myCookie');
req.session.destroy(function(err) {
req.logout();
res.redirect('/');
});
};
controllers/auth.js:
var passport = require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;
var config = require('../config');
var User = require('../models/user');
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(new BasicStrategy(
function(username, password, done) {
User.findOne({
username: username
}, function(err, user) {
if (err) {
return done(err);
}
// No user found with that username
if (!user) {
return done(null, false);
}
// Make sure the password is correct
user.verifyPassword(password, function(err, isMatch) {
if (err) {
return done(err);
}
// Password did not match
if (!isMatch) {
return done(null, false);
}
// Success
return done(null, user);
});
});
}
));
exports.isAuthenticated = passport.authenticate('basic', {
session: false
});
The problem
/signout route does not end the current session. In the req.session.destroy callback the req.session is undefined, yet a new GET request to /users acts like the session is valid.
Can someone help clear this problem out?
If, like me, you came here as a result of question title rather than full details- the answer is req.session.destroy(). I think the logout function is particular to passport.js and will not work if you are using standard express-session.
Solution
controllers/user.js:
exports.signout = function(req, res) {
if (config.debug)
console.log("user.signout()");
req.logout();
res.send(401);
};
Btw. don't mind the session(s) still being in DB immediately after the logout. Mongod checks and clears those out after 60 s.
in sign out api without using req.session.destroy() try req.logout();. I hope it will work.
In my case the server-side code was fine. It was the client-side code where I wasn't including the withCredentials parameter when making the http request.
Below is the correct working code.
// server side (nodejs)
authRouter.post("/logout",
passport.session(),
checkAuthenticationHandler,
async (req, res, next) => {
req.logOut(err => {
if (err) next(err)
res.status(http.statusCodes.NO_CONTENT).end()
})
})
// client side (reactjs)
export const logout = async () => {
const _response = await axios({
method: 'post',
url: `${authApi}/auth/logout`,
withCredentials: true
})
}