stormpath, express - check if user exists in route - express

Working with this example (https://stormpath.com/blog/build-nodejs-express-stormpath-app)
I added a route and a view to display some of any users account profile.
username: jsmith
http://localhost:3000/-jsmith (note the -)
which works fine - even if no user is logged in.
If a user doesn't exist, the app just hangs and nothing is returned.
/-jsmithxxx
Q:
How do I test if a user exist, and return to view, "User not found"?
Thanks, Rob
app.get('/-:id', function (req, res, next) {
console.log('the response will be sent by the next function ...');
var id = req.params.id;
console.log(id);
next();
},
function (req, res) {
var id = req.params.id;
req.app.get('stormpathApplication').getAccounts({ username: id }, (err, accounts) => {
if (err) throw err;
accounts.each((account, cb) => {
console.log('Found matching account:', account);
cb();
console.log('username:' + account.username)
res.render('user', {
email: account.email,
surname: account.surname,
account:account // this passes object, which can be used in view, no need to define email:account.email in server.js
});
});
});
}
);

It looks like this is what you want:
app.get('/-:id', function(req, res, next) {
var id = req.params.id;
var spApp = req.app.get('stormpathApplication');
var acc;
spApp.getAccounts({ username: id }, function(err, accounts) {
if (err) {
return res.send('An error occured. Please try again.');
}
accounts.each(function(account, cb) {
acc = account;
cb();
}, function() {
if (!acc) {
return res.send('User not found.');
}
return res.render('user', {
email: account.email,
surname: account.surname,
account:account
});
});
});
});

Related

user.setPassword is not a function - passport local mongoose

I am implementing a reset password feature on for the users of my website. However, it seems to throw this error when the user confirms new password at the reset.ejs page.
The following steps are being performed correctly:
Token sent on mail
When clicked on token, new password page opens
When user enters new password and confirm new password and hits the button to save the new password, the function in users.js user.setPassword does not work as the error is mentioned below. It is a built in function of passport-local-mongoose.
ERROR: user.savePassword is not a function
Including all the code files below:
users.js:
var express = require('express');
var router = express.Router();
var multer = require('multer');
var upload = multer({dest: './uploads'});
var passport = require('passport');
var mongoose = require('mongoose');
var LocalStrategy = require('passport-local').Strategy;
var randomstring = require("randomstring");
var User = require('../models/user');
var data=require('../models/data');
var checklist=require("../models/checklist");
var async = require("async");
var crypto = require("crypto");
var passportLocalMongoose=require("passport-local-mongoose");
// "use strict";
const nodemailer = require("nodemailer");
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.get('/register/:type', function(req, res, next) {
res.render('user/register.ejs',{title:'Register',type:req.params.type});
});
router.get('/login', function(req, res, next) {
res.render('user/login.ejs', {title:'Login'});
});
router.post('/login',
passport.authenticate('local',{failureRedirect:'/users/login', failureFlash: 'Invalid username or password'}),
function(req, res) {
var previouspath=req.cookies.previouspath;
if(req.cookies.checklist==undefined){
req.flash('success', 'You are now logged in');
if(req.user.as=='seller'){
if(previouspath!=undefined){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer');
}
else
res.redirect('/buyer');
}
else {
if(previouspath!=undefined){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer');
}
else
res.redirect('/buyer');
}
}
else{
var ids=req.cookies.checklist['data']
var checks=[];
for(var i=0;i<ids.length;i++){
checks.push({user:req.user,data:ids[i]});
}
checklist.insertMany(checks,function(err, d) {
if(err)console.log(err);
res.clearCookie('checklist');
req.flash('success', 'You are now logged in');
if(req.user.as=='seller'){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/seller')
}
else {
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer')
}
});
}
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(function(username, password, done){
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) return done(err);
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message:'Invalid Password'});
}
});
});
}));
router.post('/register/:type',function(req, res, next) {
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var institution=req.body.institution;
var education=req.body.education;
var proffession=req.body.proffession;
var country=req.body.country;
//check if email does not already exists
//check if username does not already exists
User.find({ $or: [ { email: { $eq: req.body.email } }, { username: { $eq: req.body.username } } ] },function(err,data){
if(err)console.log(err);
if(data.length!=0){
console.log(data.length);
req.flash('success','email or username is repeated.');
res.redirect('/users/register/'+req.params.type);
}
else
{
var password = req.body.password;
var password2 = req.body.password2;
var as =req.params.type;
// Form Validator
req.checkBody('name','Name field is required').notEmpty();
req.checkBody('email','Email field is required').notEmpty();
req.checkBody('email','Email is not valid').isEmail();
req.checkBody('username','Username field is required').notEmpty();
req.checkBody('password','Password field is required').notEmpty();
// Check Errors
var errors = req.validationErrors();
if(errors){
res.render('user/register.ejs', {
errors: errors
});
} else{
var newUser = new User({
name: name,
email: email,
username: username,
password: password,
as :as,
institution:institution,
education:education,
proffession:proffession,
country:country
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
// res.location('/');
var token=randomstring.generate(7);
var to=req.body.email;
var subject='Email Confirmation from dataSeed ';
var message='<h1>Use this code to register </h1><p>Your verification Code is: <h2>'+token+'</h2></p>';
var mailOptions=sendmail(to,subject,message);
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
}
else
{
res.render('user/emailconfirmation.ejs',{username:req.body.username,token:token});
}
});
}
}
});
function sendmail(to,subject,message){
var mailOptions = {
from: 'dataseedltd#gmail.com',
to: to,
subject: subject,
html: message
};
return mailOptions;
}
router.post('/emailconfirmation/:token',function(req, res) {
if(req.params.token==req.body.token){
req.flash('success', 'You are now registered and can login');
res.redirect('/');
}
else{
User.remove({username:req.body.username},function(err,data){
if(err)console.log(err);
res.redirect('/');
});
}
});
});
router.get('/logout', function(req, res){
req.logout();
req.flash('success', 'You are now logged out');
res.redirect('/users/login');
});
//Forgot Password
router.get('/forgot',function(req,res){
res.render("forgotpassword.ejs");
});
router.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('success', 'No account with that email address exists.');
return res.redirect('/users/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
var mailOptions = {
to: user.email,
from: 'dataseedltd#gmail.com',
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/users/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
console.log('mail sent');
req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.redirect('/users/forgot');
});
});
router.get('/reset/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('success', 'Password reset token is invalid or has expired.');
return res.redirect('/users/forgot');
}
res.render('reset', {token: req.params.token});
});
});
router.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
if(req.body.password === req.body.confirm) {
user.setPassword(req.body.password, function(err) {
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
})
} else {
req.flash("error", "Passwords do not match.");
return res.redirect('back');
}
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
var mailOptions = {
to: user.email,
from: 'dataseedltd#gmail.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('success', 'Success! Your password has been changed.');
done(err);
});
}
], function(err) {
res.redirect('/login');
});
});
module.exports = router;
users.js (model):
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var passportLocalMongoose=require("passport-local-mongoose");
mongoose.connect('mongodb://localhost/dataseed');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
profileimage:{
type: String
},
as:{
type:String
},
institution:{
type:String
},
education:{
type:String
},
proffession:{
type:String
},
country:{
type:String
},
resetPasswordToken: String,
resetPasswordExpires: Date
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
callback(null, isMatch);
});
}
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
It seems like you don't have a method called setPassword defined under user model. This is mainly because you haven't plugin the passport-local-mongoose to UserSchema. Add UserSchema.plugin(passportLocalMongoose); before creating the model from UserSchema. like this
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var passportLocalMongoose=require("passport-local-mongoose");
mongoose.connect('mongodb://localhost/dataseed');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
profileimage:{
type: String
},
as:{
type:String
},
institution:{
type:String
},
education:{
type:String
},
proffession:{
type:String
},
country:{
type:String
},
resetPasswordToken: String,
resetPasswordExpires: Date
});
UserSchema.plugin(passportLocalMongoose);
var User = module.exports = mongoose.model('User', UserSchema);

Bcrypt + Sequelize password not saving as hash in DB

Sequelize + Bcrypt not storing passwords in DB as hash
As the title says, whenever I attempt to store a user into my SQLite DB the console outputs the password as a hash but when I look into the DB with DBbrowser I can see the plaintext password.
Model
// const Promise = require('bluebird')
const bcrypt = require('bcrypt')
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeSave: hashPassword,
beforeCreate: hashPassword
}
})
User.prototype.comparePassword = function (password) {
bcrypt.compare(password, this.password, function (res, err) {
if (res) {
console.log(res)
} else {
console.log(err)
}
})
return bcrypt.compare(password, this.password)
}
return User
}
Controllers
module.exports = {
async register (req, res) {
try {
const user = await User.create(req.body)
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (err) {
// e-mail already exists or such
res.status(400).send({
error: 'This email address is already in use'
})
}
},
async login (req, res) {
try {
// Grab user input
const { email, password } = req.body
const user = await User.findOne({
where: {
email: email
}
})
// Check to see if user is in db
if (!user) {
res.status(403).send({
error: 'the login information was incorrect / Not Found'
})
}
// Check to see if password is valid
const isPasswordValid = await user.comparePassword(password)
if (!isPasswordValid) {
return res.status(403).send({
error: 'The login information was incorrect'
})
}
// return user using toJSON()
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (e) {
res.status(500).send({ error: 'An error occured attempting to login' })
console.log(e)
}
}
}
To elaborate a little more, whenever I create a user, I receive the following:
{
"user": {
"id": 1,
"email": 'test#test.com",
"password": "$2b$08$SYYXU/GDSCFsp3MVeuqrduI0lOLHeeub7whXiaMMoVxO53YJry.1i",
"updatedAt": "2018-09-07T22:44:12.944Z",
"createdAt": "2018-09-07T22:44:12.944Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJTVVBCUkhVQGxvbC5jb20iLCJwYXNzd29yZCI6IiQyYiQwOCRTWVlYVS9HRFNDRnNwM01WZXVxcmR1STBsT0xIZWV1Yjd3aFhpYU1Nb1Z4TzUzWUpyeS4xaSIsInVwZGF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImNyZWF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImlhdCI6MTUzNjM2MDI1MywiZXhwIjoxNTM2OTY1MDUzfQ.mDaeIikzUcV_AGTuklnLucx9mVyeScGpMym1y0kJnsg"
}
Which to me says the DB successfully hashed my password, and stored it. The overhanging issue for me with this is the fact that I believe it's causing the bcrypt.compare function to spit out 'false'. As always, any insight or help would be greatly appreciated!
I'm pretty sure that this answer is too late for you, but might help others landing on this same question.
The main issue I can see is how you are using the async/await pattern. Changing this:
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
to this, worked for me:
async function hashPassword(user, options) {
if (!user.changed("password")) {
return 0;
}
user.password = await bcrypt.hash(user.password, SALT_FACTOR);
}
Can you please try to add only one hook
hooks: {
beforeSave: hashPassword,
}
Because I think your password is getting hashed two times. as beforeSave and beforeCreate both hooks get executed.
Hope it helps

Bad Request when registering with passport

I am trying to build an authentication panel for the MEAN stack using PassportJS. I have the following code for registering new users with email(instead of the default username) and password:
router.post("/register", function (req, res) {
var newUser = new User({
username: req.body.email
});
User.register(newUser, req.body.password, function (err, user) {
if (err) {
return res.render('account/signup');
}
passport.authenticate("local")(req, res, function () {
res.redirect("/account/profile");
});
});
});
However, when running the server, I am presented with a screen on which it is written Bad Request.
It can be assumed that the new user account is being successfully created as I am able to log in that account.
I believe that the error originates somewhere around here:
passport.authenticate("local")(req, res, function () {
res.redirect("/account/profile");
});
passport.authenticate is a middleware, which means that you have to call it with 3 parameters (req, res, next):
...
passport.authenticate("local", function(err, user, info) {
if (err) return next(err);
if (!user) return res.redirect('/login');
req.logIn(user, function(err) {
if (err) return next(err);
return res.redirect("/account/profile");
});
})(req, res, next);
...
Or use it inside post method:
router.post("/register", function (req, res, next) {
var newUser = new User({
username: req.body.email
});
User.register(newUser, req.body.password, function (err, user) {
if (err) {
return res.render('account/signup');
}
// go to the next middleware
next();
});
}, passport.authenticate('local', {
successRedirect: '/account/profile',
failureRedirect: '/login'
}));

How to get socket.io to recognize when model has been updated

I'm relatively new to MEAN/Mongoose/socket.io and am missing something that seems like it'd be basic, but regardless, it's keeping me from moving forward.
I'm keeping track of a group's meetings and have the following Schema:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ScheduleSchema = new Schema({
description: String,
meetingPlace: String,
office: String,
start: { type: Date, default: Date.now },
end: { type: Date, default: Date.now },
participants: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
author: {
type: Schema.Types.ObjectId,
ref: 'User'
},
timestamp: { type: Date, default: Date.now },
active: Boolean
});
ScheduleSchema.statics = {
load: function(cb) {
this.find({})
.populate({path:'participants'})
.exec(cb);
}
};
module.exports = mongoose.model('Schedule', ScheduleSchema);
When I create a new item in the Schedule model, this code sets it in motion (from a client-side controller):
$http.post('/api/schedules', { description: info.description, participants: attendees, meetingPlace: info.meetingPlace, office: info.office, start: info.start, end: info.end, timestamp: new Date(), active: true });
And because of this code:
'use strict';
var express = require('express');
var controller = require('./schedule.controller');
var router = express.Router();
router.get('/', controller.index);
router.get('/:id', controller.show);
router.post('/', controller.create);
router.put('/:id', controller.update);
router.patch('/:id', controller.update);
router.delete('/:id', controller.destroy);
module.exports = router;
I think the request is being routed to controller.create, which is the following:
'use strict';
var _ = require('lodash');
var Schedule = require('./schedule.model');
// Get list of schedules
exports.index = function(req, res) {
Schedule.load(function (err, schedules) { /*.find*/
if(err) { return handleError(res, err); }
return res.json(200, schedules);
});
};
// Get a single schedule
exports.show = function(req, res) {
Schedule.findById(req.params.id, function (err, schedule) {
if(err) { return handleError(res, err); }
if(!schedule) { return res.send(404); }
return res.json(schedule);
});
};
// Creates a new schedule in the DB.
exports.create = function(req, res) {
var promise = Schedule.create(req.body, function(err, schedule) {
if(err) { return handleError(res, err); }
return res.json(201, schedule);
});
};
// Updates an existing schedule in the DB.
exports.update = function(req, res){
var updatedMeeting = req.body;
var id = updatedMeeting._id;
delete updatedMeeting._id;
Schedule.update({_id : id}, updatedMeeting, { }, function (err, numberAffected, raw) {
if (err) return res.json(500, err);
updatedMeeting._id = id;
return res.json(201, updatedMeeting);
});
};
// Deletes a schedule from the DB.
exports.destroy = function(req, res) {
Schedule.findById(req.params.id, function (err, schedule) {
if(err) { return handleError(res, err); }
if(!schedule) { return res.send(404); }
schedule.remove(function(err) {
if(err) { return handleError(res, err); }
return res.send(204);
});
});
};
function handleError(res, err) {
return res.send(500, err);
}
After exports.create is run, and I don't know how, but something sends it over to here:
'use strict';
var Schedule = require('./schedule.model');
exports.register = function(socket) {
Schedule.schema.post('save', function (doc) {
onSave(socket, doc);
});
Schedule.schema.post('remove', function (doc) {
onRemove(socket, doc);
});
Schedule.schema.post('update', function (doc) {
onUpdate(socket, doc);
});
}
function onSave(socket, doc, cb) {
console.log('**********onSave**********');
Schedule
.findOne({ _id : doc._id })
.populate('participants')
.exec(function (err, event) {
if (err) return handleError(err);
socket.emit('schedule:save', event);
});
}
function onRemove(socket, doc, cb) {
socket.emit('schedule:remove', doc);
}
function onUpdate(socket, doc, cb) {
console.log('**********onUpdate**********');
socket.emit('schedule:update', doc);
}
and the line socket.emit('schedule:save', event); is called.
So that's all great, but when I update the Schedule model, I can't get socket to emit 'schedule:update' because it never gets to the "onUpdate" function in the code snippet just above this.
Starting from the client-side call:
$http.patch('/api/schedules/' + info._id, { _id: info._id, description: info.description, participants: attendees, meetingPlace: info.meetingPlace, office: info.office, start: info.start, end: info.end, timestamp: new Date(), active: true });
and the router sends that to exports.update, the model is updated, but socket doesn't emit anything, so all the clients connected see the old schedule information.
How and where can I relay to socket.io that the model has been updated? I think what I'm missing is how Schedule.schema.post('some action... gets called within the exports.register function, but I've been looking at this for a while and could use a hand - thanks.

Implement Remember Me functionality in Express + PassportJS + Redis app

I'm trying to build authentication system with ExpressJS and PassportJS. For session store I use Redis. I wanna use Remember Me. Every time when the user signs in and has marked "remember me" check-box, it should automatically sign in by next visit on site. I have downloaded an example app form Github https://github.com/jaredhanson/passport-remember-me and change for my using.
var express = require('express')
, passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, mongodb = require('mongodb')
, mongoose = require('mongoose')
, bcrypt = require('bcrypt')
, SALT_WORK_FACTOR = 10
, RedisStore = require('connect-redis')(express);
mongoose.connect('localhost', 'test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
console.log('Connected to DB');
});
// User Schema
var userSchema = mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true},
accessToken: { type: String } // Used for Remember Me
});
// Bcrypt middleware
userSchema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, 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();
});
});
});
// Password verification
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if(err) return cb(err);
cb(null, isMatch);
});
};
// Remember Me implementation helper method
userSchema.methods.generateRandomToken = function () {
var user = this,
chars = "_!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
token = new Date().getTime() + '_';
for ( var x = 0; x < 16; x++ ) {
var i = Math.floor( Math.random() * 62 );
token += chars.charAt( i );
}
return token;
};
// Seed a user
var User = mongoose.model('User', userSchema);
var usr = new User({ username: 'bob', email: 'bob#example.com', password: 'secret' });
usr.save(function(err) {
if(err) {
console.log(err);
} else {
console.log('user: ' + usr.username + " saved.");
}
});
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing.
//
// Both serializer and deserializer edited for Remember Me functionality
passport.serializeUser(function(user, done) {
var createAccessToken = function () {
var token = user.generateRandomToken();
User.findOne( { accessToken: token }, function (err, existingUser) {
if (err) { return done( err ); }
if (existingUser) {
createAccessToken(); // Run the function again - the token has to be unique!
} else {
user.set('accessToken', token);
user.save( function (err) {
if (err) return done(err);
return done(null, user.get('accessToken'));
})
}
});
};
if ( user._id ) {
createAccessToken();
}
});
passport.deserializeUser(function(token, done) {
User.findOne( {accessToken: token } , function (err, user) {
done(err, user);
});
});
// Use the LocalStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a username and password), and invoke a callback
// with a user object. In the real world, this would query a database;
// however, in this example we are using a baked-in set of users.
passport.use(new LocalStrategy(function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
user.comparePassword(password, function(err, isMatch) {
if (err) return done(err);
if(isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
var app = express();
// configure Express
app.configure(function() {
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.engine('ejs', require('ejs-locals'));
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({
store: new RedisStore({ host: '127.0.0.1', port: 6379, prefix: 'chs-sess' }),
secret: '4Md97L1bL4r42SPn7076j1FwZvAiqube',
maxAge: new Date(Date.now() + 3600000)
}));
// Remember Me middleware
app.use( function (req, res, next) {
if ( req.method == 'POST' && req.url == '/login' ) {
if ( req.body.rememberme ) {
req.session.cookie.maxAge = 2592000000; // 30*24*60*60*1000 Rememeber 'me' for 30 days
} else {
req.session.cookie.expires = false;
}
}
next();
});
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(__dirname + '/../../public'));
});
app.get('/', function(req, res){
res.render('index', { user: req.user });
});
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { user: req.user });
});
app.get('/login', function(req, res){
res.render('login', { user: req.user, message: req.session.messages });
});
// POST /login
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
//
// curl -v -d "username=bob&password=secret" http://127.0.0.1:3000/login
//
/***** This version has a problem with flash messages
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res) {
res.redirect('/');
});
*/
// POST /login
// This is an alternative implementation that uses a custom callback to
// acheive the same functionality.
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
req.session.messages = [info.message];
return res.redirect('/login')
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
app.listen(3000, function() {
console.log('Express server listening on port 3000');
});
// Simple route middleware to ensure user is authenticated.
// Use this route middleware on any resource that needs to be protected. If
// the request is authenticated (typically via a persistent login session),
// the request will proceed. Otherwise, the user will be redirected to the
// login page.
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}
My app doesn't work with Remember Me, every time when I close the browser, I have to sign-in again. I don't know, what I have done wrong.
My second question is, how doe Remember Me works as usual? I have some idea but not exactly sure.