How to make a specific user log out? NodeJS-Express-MongoDB - node.js

I have admin role and when I block some user, I want to log the user out immediately.
req.session.destroy() is not the case as it log out me. Thanks in advance.
app.js
mongoose.connect('mongodb://127.0.0.1/nodeblog_db', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
app.use(expressSession({
secret: 'testotesto',
resave: false,
saveUninitialized: true,
store: connectMongo.create({mongoUrl : 'mongodb://127.0.0.1/nodeblog_db'})
}))
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
login route
router.get('/login', (req, res) => {
res.render('site/login');
});
router.post('/login', (req, res) => {
const { email, password } = req.body;
User.findOne({ email }, (error, user) => {
if (user) {
user.comparePassword(password, (matchError, isMatch) => {
if (matchError) {
throw matchError;
}
else if (isMatch) {
req.session.userId = user._id; //**************
res.redirect('/');
}
else if (!isMatch) {
res.redirect('/users/login');
}
})
}
else {
res.redirect('/users/register');
}
});
});
My User Model
I have a banned field in my database. When I want to block a user, I set that field as true.
const mongoose = require('mongoose');
const bcrypt = require("bcryptjs");
const UserSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
verified: { type: Boolean, default: false },
auth: { type: String, default: false },
banned: { type: Boolean, default: false }
});
UserSchema.pre("save", function (next) {
const user = this
if (this.isModified("password") || this.isNew) {
bcrypt.genSalt(10, function (saltError, salt) {
if (saltError) {
return next(saltError)
} else {
bcrypt.hash(user.password, salt, function (hashError, hash) {
if (hashError) {
return next(hashError)
}
user.password = hash
next()
})
}
})
} else {
return next()
}
})
UserSchema.methods.comparePassword = function (password, callback) {
bcrypt.compare(password, this.password, function (error, isMatch) {
if (error) {
return callback(error)
} else {
callback(null, isMatch)
}
})
}
module.exports = mongoose.model('User', UserSchema);
I use this code to check if user is logged in:
if(req.session.userId){
//the user is logged in
}

So The Default way I would try solving this is to add a middleware after the auth check
This is because am sure its gonna contain req.session.userId = user._id;
// Import Your Db Model
const checkBan = (req,res,next)=>{
// If you don't pass your user state into req.user
User.findOne({ _id:req.session.userId }, (error, user) => {
if(error){
next(err)
}else{
// The User Would have been authenticated
// Therefore User exist
if(user.banned){
// User Is Banned so handle it as you like
res.send("Your Account is banned - other messages")
}else{
// Users Aren't Banned so continue
next()
}
}
})
}
module.exports = checkBan;
You Can Now Import this After your Authentication checker middleware on routes you want the banned user to be unable to access
Now when you change the state to ban its renders this message and hinders any further interaction with your system from the user

Related

How to use bcrypt.compare in sails js schema?

I have a user model like this:
module.exports = {
attributes: {
email: {
type: 'string',
isEmail: true,
unique: true,
required: true
},
password: {
type: 'string',
required: true
}
},
beforeCreate: (value, next) => {
bcrypt.hash(value.password, 10, (err, hash) => {
if (err){
throw new Error(err);
}
value.password = hash;
next();
});
},
};
Now when I want to match the password during login, how do I decrypt the password, if possible I would prefer to perform it in the user model file.
controller/ login.js
module.exports = {
login: async (req, res) => {
try{
const user = await User.findOne({email: req.body.email});
if (!user){
throw new Error('Failed to find User');
}
// here I want to match the password by calling some compare
//function from userModel.js
res.status(201).json({user: user});
}catch(e){
res.status(401).json({message: e.message});
}
},
};
first try to find the user with the given username by user
const find = Users.find(user=>user.username===req.body.username)
if(!find){
res.send('User Not Found')
}
else{
if( await bcrypt.compare(req.body.password,find.password)){
//now your user has been found
}
else{
//Password is Wrong
}
}
You must use bcrypt.compare(a,b)
a = given password by user
b = original password if username exist
hope it solve your problem

Mongoose not returning anything hanging until connection timesout

My login script was working fine but only for one record, all the rest hang and do not return not quite sure why?
It reutrns the email and password from my console.log but not the console.log of the user. Also can confirm that the users email does exist in the db
Below is my basic setup.
User model
var mongoose = require("mongoose");
var bcrypt = require("bcrypt");
var passwordString = require("../helper/generateStrongRandomString");
var schema = new mongoose.Schema(
{
email: {
type: String,
required: true,
unique: true,
validate: {
validator: function (v) {
return /^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/.test(
v
);
},
message: (props) => `${props.value} is not a valid email address`,
},
},
organisation: {
ref: "organisation",
type: mongoose.Schema.Types.ObjectId,
required: true,
},
client: {
ref: "client",
type: mongoose.Schema.Types.ObjectId,
required: false,
},
forename: {
type: String,
},
surname: {
type: String,
},
password: {
type: String,
default: null,
},
created: {
type: Date,
default: Date.now(),
},
updated: {
type: Date,
default: null,
},
passwordResetString: {
type: String,
default: null,
},
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
schema.pre("save", function (next) {
var user = this;
if (!user.isNew) {
user.updated = Date.now();
}
if (user.isNew && !user.password) {
user.passwordResetString = passwordString();
}
if (!user.isModified("password")) {
return next();
}
bcrypt
.hash(user.password, 12)
.then((hash) => {
user.password = hash;
next();
})
.catch((err) => console.log(err));
});
schema.pre("save", function (next) {
var user = this;
user.updated = Date.now();
next();
});
function autopopulate(next) {
this.populate("organisation");
this.populate("client");
next();
}
schema.pre("find", autopopulate);
schema.pre("findOne", autopopulate);
var User = new mongoose.model("user", schema);
module.exports = User;
Login route
const router = require("express").Router();
const passport = require("passport");
const catchErrors = require("../middlewares/catchErrors");
router.post(
"/login",
passport.authenticate("local"),
catchErrors(async (req, res) => {
console.log(req.body);
// console.log(req);
})
);
module.exports = router;
Passport js local authentication
passport.use(
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async function (email, password, cb) {
console.log(email, password);
return User.findOne({ email })
.then((user) => {
console.log(user);
if (!user || !bcrypt.compareSync(password, user.password)) {
console.log(26);
return cb(null, false, {
message: "incorrect email or password",
});
}
return cb(null, user, {
message: "Logged in successfully",
});
})
.catch((err) => console.log(err));
}
)
);
For anyone else who stumbles across this, I figured it out. My problem was with my autopopulate and the organisation model not shown above see code below.
function autopopulate(next) {
this.populate("organisation");
this.populate("client");
next();
}
This loads and populates the organisation as part of the user data however my organisation was doing the exact same thing when it was loaded on the user and causing an infinite loop.
Lots of commenting out of code and checking to confirm.
Look out for infinite loops.

access the user._id in nodejs

I'm pretty new with node.js and I'm trying to implement simple user registration and login form using Node.js, Express, bcrypt, express-session and mongoose.
Whenever the user log in, I want to set the value of req.session.userID to user's id. When I trace the code I can't find the problem. I followed up the tutorial in this link and everything seems to be similar.
Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt');
var userSchema = new Schema({
teamName: {
type: String,
unique: true,
trim: true,
required: true
},
faculty: {
type: String,
required: true
},
email: {
required: true,
unique: true,
trim: true,
type: String
},
password: {
required: true,
type: String
},
score: {
type: Number,
default: 0
}
});
userSchema.pre('save', function(next) {
var user = this;
bcrypt.hash(user.password, 10, function(err, hash) {
if (err) return next(err)
user.password = hash;
next();
});
});
userSchema.statics.authenticate = (email, password, callback) => {
userModel.findOne({email: email}, (err, user) => {
if (err) return callback(err);
else if (!user) {
console.log('User not found!')
}
else {
bcrypt.compare(password, user.password, (err, result) => {
if (result) {
callback(null, true)
}
else {
return callback()
}
})
}
})
}
var userModel = mongoose.model('User', userSchema);
module.exports = userModel;
server:
var userModel = require('./../models/users');
router.post('/login', (req, res) => {
var email = req.body.email;
var password = req.body.password;
userModel.authenticate(email, password, (err, user) => {
console.log(user)
if (err) {
console.log(err)
}
else if (!user) {
console.log('Wrong Password')
}
else {
req.session.userId = user._id;
console.log(req.session.userId);
}
})
});
Where I have logged the value of req.session.userId it returns undefined! Where is the problem?
The problem is that the callback is returning TRUE. the callback should be returning the user data. callback(null, user)
bcrypt.compare(password, user.password, (err, result) => {
if (result) {
callback(null, true)
}
Should be
bcrypt.compare(password, user.password, (err, result) => {
if (result) {
callback(null, user)
}

Node JS Authentications with passport-jwt unauthorized

Im trying to setup my Node JS API.
I have a User model :
// Dependencies
var restful = require('node-restful');
var mongoose = restful.mongoose;
var bcrypt = require('bcrypt');
// Schema
var userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true},
firstname: {
type: String,
required: true
},
lastname: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true
},
password: {
type: String,
required: true},
},
{
timestamps: true
});
// Saves the user's password hashed
userSchema.pre('save', function (next) {
var user = this;
if (this.isModified('password') || this.isNew) {
bcrypt.genSalt(10, function (err, salt) {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
} else {
return next();
}
});
// Use bcrypt to compare passwords
userSchema.methods.comparePassword = function(pw, cb) {
bcrypt.compare(pw, this.password, function(err, isMatch) {
if (err) {
return cb(err);
}
cb(null, isMatch);
});
};
module.exports = restful.model('Users', userSchema);
I want to use passport with jwt for authentication :
// Dependencies
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var config = require('../config/database');
// Load models
var User = require('../models/user');
// Logique d'authentification JWT
module.exports = function(passport) {
var opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('JWT');
opts.secretOrKey = config.secret;
opts.audience = 'localhost';
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
User.findById(jwt_payload._id, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
Company.findById(jwt_payload._id, function(err, company) {
if (err) {
return done(err, false);
}
if (company) {
done(null, company);
} else {
done(null, false)
}
});
}));
};
And my route for authentication :
// User
router.post('/users/login', (req, res) => {
User.findOne({
email: req.body.email
}, (err, user) => {
if (err) throw err;
if (!user) {
res.json({success: false, message: 'Authentication failed. User not found.'});
} else {
// Check if passwords matches
user.comparePassword(req.body.password, (err, isMatch) => {
if (isMatch && !err) {
// Create token if the password matched and no error was thrown
var token = jwt.sign(user, config.secret, {
expiresIn: 10080 // in seconds
});
res.json({success: true, token: 'JWT ' + token, user: {
id: user._id,
username: user.username,
email: user.email
}});
} else {
res.json({success: false, message: 'Authentication failed. Passwords did not match.'});
}
});
}
});
});
Everything work great on postman.
The token is correctly generated and signed with user's informations.
But i have a problem with the authentication on a protected route :
router.get('/users/profile', passport.authenticate('jwt', { session: false }), function(req, res) {
res.send('It worked! User id is: ' + req.user._id + '.');
});
Everytime, it gives me an "Unauthorized 401" Error.
I really dont know where is the problem, i think the problem is around jwtFromRequest, i also tried with Bearer but it also doesn't work...
I think a good option to avoid this kind of problems is to start from a base project that uses this authentication strategy, and after you have that working, modify it with your functionality.
Here you have an example with jwt authentication strategy and Refresh token implementation: https://solidgeargroup.com/refresh-token-autenticacion-jwt-implementacion-nodejs?lang=es

passportjs user object does not return password for compare password

I have an issue that I am not getting an idea that why user stored object does not return password in validatePassword function in model/user.js. I followed all steps described in passportjs official documentation.
I used localstategy of passportjs for signin. When I compare email it always compare but when I tried to execute validate password and use this.password or as a argument it always blank and that is why my password is not compare.
I got all user schema information but I does not get password in user object so I am not able to compare it.
Can anyone tell how could I get out of this issue?
Console Log
root#wk11:/var/www/html/mytripmean/trunk# nodejs server.js
Mytrip is listening on port 1000
MongoDB connection successful
---- User Information ----
myemail#gmail.com
Password##123
{ message: 'Incorrect password.' }
not user:
false
[Error: Illegal arguments: string, undefined]
/var/www/html/mytripmean/trunk/app/data/models/user.js:105
throw err;
^
Error: Illegal arguments: string, undefined
at Error (<anonymous>)
at Object.bcrypt.compare (/var/www/html/mytripmean/trunk/node_modules/bcryptjs/dist/bcrypt.js:250:42)
at model.userSchema.methods.validPassword (/var/www/html/mytripmean/trunk/app/data/models/user.js:102:12)
at Query.<anonymous> (/var/www/html/mytripmean/trunk/app/data/routes/user.js:222:27)
at /var/www/html/mytripmean/trunk/node_modules/kareem/index.js:177:19
at /var/www/html/mytripmean/trunk/node_modules/kareem/index.js:109:16
at process._tickCallback (node.js:448:13)
models/user.js
var mongoose = require('mongoose')
, Schema = mongoose.Schema
, ObjectId = Schema.ObjectId
, randtoken = require('rand-token')
, bcrypt = require("bcryptjs");
var userSchema = new Schema({
// _Id: objectId,
social_id: {
type: String, //(Social id of facebook/twitter)
required: false,
unique: false
},
social_media: {
type: String, //(facebook/twitter)
required: false,
unique: false
},
link_id: {
type: String, //will be dispalying as user reference in url
required: true,
unique: true
},
nick_name: {
type: String, // Unique Nickname for signup
required: true,
unique: true
},
email: {
type: String, // Unqiue Email for signup
required: true,
unique: true
},
password: {
type: String, // Password
required: true,
select: false
},
user_type: {
type: Number, // 1: SuperAdmin, 2: Admin, 3: SiteUser, 4: Restaurant
required: true
}, //reason_to_close: String, // Close Account
is_active: {
type: Number, // -1: pending to activation, 0: inactive, 1: active,
required: true
},
is_close: {
type: Number, // -1: pending to close/Undecided, 0: closed , 1: open/ not close,
required: true
},
is_online: {
type: Number, // 0: Offline, 1: Online
required: true
},
created_at: {
type: Date,
default: Date.now
}, // Registration date
updated_at: {
type: Date, // Registration activation date / user update date
default: Date.now
}
}, {collection: 'user'});
// Password verification
userSchema.methods.validPassword = function (candidatePassword, callback) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
console.log(err);
if (err) {
throw err;
}
callback(null, isMatch);
});
};
var User = module.exports = mongoose.model("User", userSchema);
module.exports.checkEmail = function (callback) {
return this.model('User').count({email: this.email}, callback);
};
module.exports.validateEmailOrNickname = function (username, callback) {
var orCondition = [{nick_name: username}, {email: username}];
//return this.model("user").findOne().or(orCondition);
return this.model("User").find({$or: orCondition}, callback);
};
module.exports.getUserById = function (id) {
User.findById(id, callback);
};
module.exports.createUser = function (user, callback) {
bcrypt.genSalt(10, function (err, salt) {
bcrypt.hash(user.password, salt, function (err, hash) {
user.password = hash;
user.save(callback);
});
});
};
routes/user.js
var express = require('express');
var router = express.Router();
var bcrypt = require("bcryptjs")
var User = require('../models/user');
var UserProfile = require('../models/userProfile');
var UserSignupToken = require('../models/userSignupToken.js');
var IpLogger = require('../models/ipLogger.js');
var passport = require("passport");
var localStrategy = require("passport-local"), Startegy;
router
.route('/api/user/register')
.post(
function (req, res, next) {
var user_, userData_;
userData_ = {
link_id: req.body.manLinkId,
nick_name: req.body.txtNickname,
email: req.body.txtEmail,
password: req.body.manPassword,
user_type: req.body.manUserType,
is_active: req.body.manIsActive,
is_close: req.body.manIsClose,
is_online: req.body.manIsOnline
};
user_ = new User(userData_);
user_.validate(function (err) {
if (err) {
} else {
//check recaptch is validate or not
var request = require('request');
request
.post({
url: 'http://www.google.com/recaptcha/api/verify',
form: {
privatekey: process.env.RECAPTCHA_PRIVATE_KEY,
remoteip: req.connection.remoteAddress,
challenge: req.body.captcha.challenge,
response: req.body.captcha.response
}
}, function (err, httpResponse, body) {
if (body.match(/false/) === null) {
//Recaptcha validated
User.createUser(user_, function (err, data) {
if (err) {
console.log("stpe 1:");
console.log(err);
res.json({status: 0, message: 'User having an error on stage 1'});
} else {
res.locals.user = data;
//res.json({error:1, message: 'User saved'});
next();
}
});
//res.json({ "captchaError": true });
} else {
res.json({"captchaError": false});
}
});
}
});
},
function (req, res, next) {
var userProfileData_, userProfile_;
userProfileData_ = {
user_id: res.locals.user.id,
link_id: res.locals.user.link_id,
full_name: req.body.txtFullname,
is_active: -1
};
userProfile_ = new UserProfile(userProfileData_);
userProfile_.save(function (err, data) {
if (err) {
console.log("stpe 2:");
console.log(err);
res.json({status: 0, message: 'User having an error on stage 2'});
} else {
//res.json({error:1, message: 'User profile generated'});
next();
}
});
},
function (req, res, next) {
var userSignupTokenData_, userSignupToken_;
userSignupTokenData_ = {
user_id: res.locals.user.id,
link_id: res.locals.user.link_id,
is_active: -1
};
userSignupToken_ = new UserSignupToken(userSignupTokenData_);
userSignupToken_.save(function (err, data) {
if (err) {
console.log("stpe 3:");
console.log(err);
res.json({status: 0, message: 'User having an error on stage 3'});
} else {
//res.json({error:1, message: 'User signup token generated'});
next();
}
});
},
function (req, res, next) {
var ipLoggerData_, ipLogger_, client_IP;
ipLoggerData_ = {
user_id: res.locals.user.id,
link_id: res.locals.user.link_id,
client_ip: req.ip,
activity: "signup"
};
ipLogger_ = new IpLogger(ipLoggerData_);
ipLogger_.save(function (err, data) {
if (err) {
console.log("stpe 4:");
console.log(err);
res.json({status: 0, message: 'User having an error on stage 4'});
} else {
res.json({status: 1, message: 'user saved'});
}
});
}
);
//Check unique validation
router
.route('/api/user/authenticate')
.post(
function (req, res, next) {
console.log("---- User Information ----");
console.log(req.body.txtSigninEmail);
console.log(req.body.txtSigninPassword);
passport.authenticate('local', function (err, user, info) {
console.log(info);
if (err) {
console.log(err);
return next(err);
}
if (!user) {
console.log("not user:");
console.log(user);
return res.status(401).json({
err: info
});
}
req.login(user, function (err) {
if (err) {
return res.status(500).json({
err: 'could not login user'
});
}
res.status(200).json({
status: 'login successful'
});
});
})(req, res, next);
});
router
.route('/api/user/checkEmail')
.post(
function (req, res) {
User.count({email: req.body.txtSigninPassword}, function (err, user) {
if (err) {
// console.log("error false");
res.json(false);
} else {
// console.log("data");
// console.log(user);
res.json({"status": user > 0 ? false : true});
}
});
});
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('local', new localStrategy(
{
usernameField: 'txtSigninEmail',
passwordField: 'txtSigninPassword'
},
function (username, password, done) {
User.findOne({email: username}, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {message: 'Incorrect username.'});
}
if (!user.validPassword(password)) {
return done(null, false, {message: 'Incorrect password.'});
}
return done(null, user);
});
}
));
module.exports = router;
After 2 hours of efforts I found answer of my question. In my User model password field, I set property "select:false", due to that I always get a password as blank.
Older:
var userSchema = new Schema({
password: {
type: String, // Password
required: true,
select: false
},
}
After re-setting select: true it works fine.
Updated:
var userSchema = new Schema({
password: {
type: String, // Password
required: true,
select: true
},
}

Resources