I have got the mongo db commands from the below link.
http://try.mongodb.org/
I have a project and I am able to run it. In the project we use mongodb, angular js, node js and express server.
I am able to create user from the login page.The users are stored in mongo db. I would like to know what are the users in the database.
Initially I did not install any mongodb. But some how, the user and password was stored in localhost. I hope my project will be having certain libraries.
But later, in order to learn mongo, i installed mongo to my PC. I started the mongo db and it is running successfully in the link
http://localhost:28017/.
MongoDB starting : pid=6300 port=27017 dbpath=\data\db\ 64-bit host=new-PC
Question 1
I would like to list out the users in the db, that is used by my project. Will installation of mongo db help me in some way? If not without starting mongo db, can i know where are the user details saved by my project?
Question 2
How can I set up mongo db in remote so that it is available in the internet?
Code
- Creating UserSchema
var UserSchema = new Schema({ name: String, email: { type: String, unique: true }, hashed_password: String, provider: String, salt: String, facebook: {}, twitter: {}, github: {}, google: {} });
mongoose.model('User', UserSchema);
- Code for creating user
var mongoose = require('mongoose'), User = mongoose.model('User'), q = require('q'), _ = require('lodash');
exports.create = function(req, res, next) { var reqUser = new User(req.body); var email = reqUser.email; if(!reqUser.email) { res.send(400, {message: 'Email is mandatory!'}); }
var message = null;
reqUser.provider = 'local';
var savePromise = q.when(User.findOne({'email': reqUser.email}).exec());
savePromise.then(function(user) {
return reqUser;
if(user == null)
{
return reqUser;
} else
{
if(reqUser.provider!=user.provider && !user.hashed_password)
{
user.password = reqUser.password;
} else {
throw new Error("User alredy exists!");
}
console.log("In Else");
console.log(user);
return user;
}
}, function(err){
console.log("In Error 1");
}
).then(function(user){
console.log("In then 2");
console.log(user);
return user.save();
}, function(err){
console.log("In error 2");
console.log(err);
}).then(function(obj){
console.log("In then 3");
console.log(obj);
}).fail(function(error){
console.log("In Fail");
console.log(error);
}).done(function(){
// console.log(user);
console.log("in done");
});
console.log("Returning 400 at the end");
user.save(function(err) {
if (err) {
console.log(err);
message = 'Unknowd error occured, please try again!';
if(err.code=11000)
{
message = 'User with this email already exist. Existing user? please login here';
User.findOne({
email: user.email
}, function(err, dbuser) {
if (err) {
return res.json(400, { message: message });
}else {
if(dbuser.provider!=user.provider)
{
console.log("In If");
console.log(dbuser);
if(!dbuser.hashed_password)
{
console.log("In another if");
dbuser.password = user.password;
dbuser.save(function(err){
if(err)
{
console.log(err);
}
return res.json(dbuser);
});
}else
{
console.log("Returning error");
return res.json(400, { message: message })
}
} else
{
return res.json(400, { message: message });
}
}
});
}
}else
{
return res.json(user);
}
//console.log("Returning success");
});
};
Thanks,
Sabarisri
To answer question #2 first,
you will need either an instance of mongoDB on your own server or get a hosted one.
See for example Database-as-a-service. There are quite a lot of possibilites, check out some other offers.
Your first question is confusing me. It would be helpful to see the code that creates a user.
Installation:
http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/
Coding :
http://docs.mongohq.com/languages/nodejs.html
How to secure MongoDB with username and password
Related
I am trying to have a user log in by their email and password. MongoDb docs shows hashing the password with bcrypt in the user model. It also provides a nice way to validate the password in the model as well. My problem is how to I use that validation from the "controller"? I am very aware "if (req.body.password === user.password)" will not work because one is hashed and the other is not.
I have been searching for answers for hours and can't seem to find that connection on how I use that "UserSchema.methods.comparePassword" method in my post request to log in. This isn't completely a real log in, just trying to get the password to validate and send back a key once logged in. Here are the docs: https://www.mongodb.com/blog/post/password-authentication-with-mongoose-part-1
// This is my UserModel
let mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt'),
SALT_WORK_FACTOR = 10
var hat = require('hat');
let UserSchema = new Schema({
email: {
type: String,
required: true,
index: {
unique: true
}
},
password: {
type: String,
require: true
},
api_key: {
type: String
}
});
UserSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
user.api_key = hat();
next();
});
});
});
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('user', UserSchema);
// This is the sessions.js
let UserModel = require('../../../models/user.model');
var express = require('express');
var router = express.Router();
router.post('/', (req, res, next) => {
UserModel.findOne(
{
$or: [
{ email : req.body.email }
]
}
)
.then(user => {
if (req.body.password === user.password) {
res.setHeader("Content-Type", "application/json");
res.status(200).send(JSON.stringify({
"api_key": `${user.api_key}`
}));
} else {
res.status(404).send("Incorrect email or password")
}
})
.catch(error => {
res.setHeader("Content-Type", "application/json");
res.status(500).send({error})
})
})
module.exports = router
If I just find user by email, everything works fine. Just need to figure out how to use the compare password method in the user model. Thanks!
Maybe have something like this in your model:
User = require('./user-model');
.......
User.findOne({ username: 'jmar777' }, function(err, user) {
if (err) throw err;
user.comparePassword('Password123', function(err, isMatch) {
if (err) throw err;
console.log('Password123:', isMatch); // -> Password123: true
});
........
Other resources:
http://devsmash.com/blog/password-authentication-with-mongoose-and-bcrypt
https://www.abeautifulsite.net/hashing-passwords-with-nodejs-and-bcrypt
https://medium.com/#mridu.sh92/a-quick-guide-for-authentication-using-bcrypt-on-express-nodejs-1d8791bb418f
Hope it helps!
I know this question has been asked many times but I cannot find an answer to my problem both here or on github. I have a login handler which compares hashed password from db to the the one typed by the user on login. bcrypt.compare almost always returns false. I say almost because sometimes it just starts working and it always works after I register user. I am trying to find what is wrong with my code but cant figure it out. Any help is highly appreciated.
mongoose pre save
userModel.schema.pre('save', function(next) {
let user = this;
bcrypt.hash(user.password, 10, null)
.then(hash => {
console.log(hash)
user.password = hash;
user.confirmPassword = hash;
next();
})
.catch(err => res.sendStatus(404));
});
login handler
exports.loginUser = (req, res) => {
let user = new User.model(req.body);
User.model
.find({email: user.email})
.exec()
.then(users => {
if (!users.length) {
res.status(401).json({
message: "Auth failed - user does not exist"
});
} else {
bcrypt
.compare(req.body.password, users[0].password)
.then(result=> {
console.log(user.password, users[0].password)
console.log(bcrypt.hashSync(req.body.password, 10))
if (result) {
const token =
jwt
.sign({ email: users[0].email, id: users[0]._id },
'secretKey', { expiresIn: "1h"});
res.status(200).json({
message: "Auth success - logged in",
token,
users
});
} else {
res.json('not working');
}
})
.catch(err => res.status(401).json({message: "Auth failed"}));
}
});
};
register handler
exports.registerUser = (req, res) => {
let user = new User.model(req.body);
if(user.email) {
User.model
.find({email: user.email})
.exec()
.then(docs => {
if (!docs.length) {
if (user.password !== user.confirmPassword) {
return res.status(404).json('passwords do not match');
}
user.save(function (err, user) {
if (err) return (err);
});
console.log('user saved');
res.sendStatus(200);
} else {
res.status(404).json('user exists');
}
})
.catch(err => res.sendStatus(404).json(res.body));
} else {
res.status(404).json('user name required');
}
};
The problem might be that you generate a new password each time the user is saved. You should skip this though.
userModel.schema.pre('save', function(next) {
let user = this;
if(!user.isModified("password")) return next();
bcrypt.hash(user.password, 10, null)
.then(hash => {
console.log(hash)
user.password = hash;
user.confirmPassword = hash;
next();
})
.catch(err => res.sendStatus(404));
});
Just a shot in the dark though. under the assumption something got changed and this was called again, because you stated it is working sometimes.
I'm trying to save students records, but it should not take duplicate records. How is it possible? In below code i have tried to do
app.post("/save",function(req,res){
var std=new student(req.body);
student.findOne({},function(err,success){
if(err)
{
console.log(err);
}
else
{
// console.log(success);
std.save(function(err,success){
if(err)
{
console.log(err);
}
else
{
console.log("inserted");
console.log(success);
}
});
}
})
});
Here is the sample code. Please note that the existence of the value in MongoDB database depends on the req.body as mentioned in the OP.
In the below code, I have only name attribute in the Student collection. So, the duplicate check is based on the name attribute only.
You may need to change the code if you would like to check for the specific attribute in the collection to determine the duplicate value.
Please note that my Student collection has only attribute in the schema as well.
var express = require('express');
var MongoClient = require('mongodb').MongoClient;
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Student = mongoose.model('Student', { name: String });
var app = express();
var bodyParser = require('body-parser');
var app = express();
var urlencoded_body_parser = bodyParser.urlencoded({
extended: true
});
app.use(bodyParser.json());
app.use(urlencoded_body_parser);
app.post("/save", function (req, res) {
console.log(req.body);
var student = new Student(req.body);
Student.findOne(req.body, function (err, success) {
if (err) {
console.log(err);
res.send(err);
}
else {
console.log(success);
if (success == null) {
student.save(function (err, success) {
if (err) {
console.log(err);
res.send(err);
}
else {
console.log("inserted");
console.log(success);
res.send("success");
}
});
} else {
res.send("Student already present");
}
}
})
});
app.listen(3000);
Output:-
First time execution:-
Input:-
{
"name" : "john"
}
Output:-
success
Subsequent executions with the same input json:-
Output:-
Student already present
I have had many problems, when I want to get information from user model. I read some solutions, but I didnt understand.
This is my code:
* AuthController
var passport = require('passport');
module.exports = {
_config: {
actions: false,
shortcuts: false,
rest: false
},
login: function(req, res) {
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message: info.message,
user: user
});
}
req.logIn(user, function(err) {
if (err) res.send(err);
return res.send({
message: info.message,
user: user
});
});
})(req, res);
},
logout: function(req, res) {
req.logout();
res.redirect('/');
},
signup: function (req, res) {
var data = req.allParams();
User.create({email:data.email,password:data.password,name:data.name}).exec(function(error,user){
if(error) return res.negotiate(err);
if(!user)return res.negotiate(err);
return res.ok();
});
}
};
*view
<h1>List of my dates</h1>
<h1><%= email %></h1>
<h1><%= req.user.name %></h1>
*model
attributes: {
email: {
type: 'email',
required: true,
unique: true
},
password: {
type: 'string',
minLength: 6,
required: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
beforeCreate: function(user, cb) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
console.log(err);
cb(err);
} else {
user.password = hash;
cb();
}
});
});
}
};
Only works if I use res.render('view', {email: req.user.email}) but, I would like to use the user data in many views. I cant write methods with Current user params, becouse dont work.
Thanks.
It is unclear to me what your actual problem is or what the question actually is but I will try to help.
Look here:
login: function(req, res) {
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message: info.message,
user: user
});
}
...
})(req, res);
},
There you are adding data (locals) to the ejs and the values are message and user so in the ejs you must reference it as this, so you will use user.name and not req.user.name? I'm not sure why you're binding the (req, res) either.
It's confusing because your ejs uses the email value but I don't see it there as a local so maybe thats your problem, it must be defined?
Consider the following simple example:
// User Controller
// GET request /signin
// The signin form
signin(req, res) {
// Load the view from app/views/*
return res.view('signin', {
title: 'Sign In'
});
},
// POST request to /signin
// This was posted from the signin form
// Use io.socket.post(...) to do this from the signin form
// Can use window.location.replace('/account') on successful request
authenticate(req, res) {
// The data posted, email and password attempt
var data = req.allParams();
// Does it match?
User.findOne({
email: data.email,
// This is stupid, don't ever use plain text passwords
password: data.password
})
.exec(function(err, user) {
// Server related error?
if (err) res.serverError(err.message);
// No user was found
if (!user) res.badRequest('Username or password not found');
// Sign the user in
req.session.userId = user.id;
// User was found
res.ok();
});
},
// GET request to /account
// Displays the users information
// Can use policies to ensure that only an authenticated user may access their own account information
account(req, res) {
// If the user is not signed in
// This is an alternative to using the sails policy isLoggedIn
if (!req.session.userId) res.redirect('/signin');
// Get the users details
User.findOne({
id: req.session.userId
})
.exec(function(err, user) {
// Server related error?
if (err) res.serverError(err.message);
// No user was found
if (!user) res.redirect('/signin');
// Load the ejs file that displays the users information
return res.view('account/index', {
title: 'Account Information',
user: user
});
});
},
// Account View
<p>Email: {{user.email}}</p>
<p>Password: {{user.password}}</p>
Check this out if you want to deal with password encryption: http://node-machine.org/machinepack-passwords
And this if you want to deal with the strength tests (when the user sets the password): https://www.npmjs.com/package/owasp-password-strength-test
This is as passport seems overkill if you're only doing local authentication?
I am using Sails and Waterline ORM with Mongo Database .
I have two models User and Profile with One to One relationship.
Below is the code I've written for Transaction with Rollback logic. I think there can be a much better logic than this as the current logic is very clumsy.
Questions :
Does Waterline or Sails provide any functionality for Rollback purpose?
Is there any better way of doing this ?
User.create(newUser).then(function (data) {
var newProfile = {
displayName: data.name,
email: data.email,
user: data._id
}
return Profile.create(newProfile);
}).then(function (profileData) {
sails.log.info("Profile Data " + JSON.stringify(profileData));
// Update the user with Profile Info
User.update(newUser._id, {profile: profileData._id}).then(function (updatedUser) {
return updatedUser;
}, function (err) {
// TODO Rollback logic if the User Updation Fails
})
}, function (err) {
sails.log.error("Failed to Create Profile for the User . Deleting the created User");
var criteria = {
email: data.email
}
User.destroy(criteria).then(function (user) {
sails.log.error("Deleted the Created User " + JSON.stringify(user));
throw new Error("ERROR CREATING User");
}, function (err) {
sails.log.error("ERROR DELETING USER");
throw new Error("ERROR DELETING USER", err);
})
});
To question 1 : no.
I would be tempted to do something like this:
async.waterfall([
function(callback){
User.create(newUser).then(function(data){
callback(null, data);
})
.catch(function(err){
callback(err, null, null); // don't need to rollback anything
})
},
function(data, callback){
Profile.create({
displayName: data.name,
email: data.email,
user: data._id
})
.then(function(profile){
callback(null, data, profile)
})
.create(function(err){
callback(err, data._id, null); // only need user's id
})
},
function(userData, profileData, callback){
User.update(userData._id, {profile: profileData._id})
.then(function(updatedUser){
callback(null, updatedUser);
})
.catch(function(err){
callback(err, userData._id, profileData._id); // can roll back both
})
}
], function(err, userData, profileData){
if(err) {
sails.log.error(err);
// do rollback, userData is user's ID, profileData is profile id
// if either one is undefined, then it doesn't exist
} else {
// userData is user object from the last update, return it!
}
})
I don't know if it is better, but it seems more readable, and it handles the errors for any of the three writing phases.