I have a middleware isAuthenticated to ensure that the user is logged in before he can post a comment:
function isAuthenticated(req,res,next) {
req.isAuthenticated ? next() : res.redirect('/login');
}
This middleware is suppose to be running here:
router.post('/cat/:id', isAuthenticated, function(req,res) {
console.log('not suppose to be here');
var id = req.params.id;
Cat.findById(id, function(err, cat) {
if (err) {
console.log(err);
} else {
var id = req.params.id;
var comment = new Comment({
username: req.user.username,
content: req.body.content
});
//more code
However, when I try to post a comment without logging in, my app crashes and the console shows the following:
not suppose to be here
username: req.user.username,
^
TypeError: Cannot read property 'username' of undefined
I refactored all the routes into a separate file, and exported it to app.js. All routes pertaining to cats are stored in cats.js:
var express = require('express');
var router = express.Router();
var passport = require('passport');
var Cat = require('../models/cat.js');
var Comment = require('../models/comment.js');
var mongoose = require('mongoose');
router.use(function(req,res,next) {
res.locals.user = req.user;
next();
});
function isAuthenticated(req,res,next) {
req.isAuthenticated ? next() : res.redirect('/login');
}
router.get('/cat/:id', function(req,res) {
var id = req.params.id;
Cat.findById(id, function(err, cat) {
if (err) {
console.log(err);
} else {
Comment.find({}, function(err, comments) {
if (err) {
console.log(err);
} else {
res.render('show', {cat:cat, comments:comments});
}
});
}
});
});
//more code
module.exports = router;
app.js:
var app = express();
var bodyParser = require('body-parser');
var config = require('./config/config.js');
var mongoose = require('mongoose');
var Cat = require('./models/cat.js');
var Comment = require('./models/comment.js');
var session = require('express-session');
var passport = require('passport');
var LocalStrategy = require('passport-local');
var passportLocalMongoose = require('passport-local-mongoose');
var User = require('./models/user.js');
mongoose.connect(config.dbURL, function(err) {
if (err) {
console.log(err);
} else {
console.log('successfully connected to database!');
}
});
app.set('view engine', 'ejs');
app.use(session({
secret:"sfsdfsdfsd",
resave: false,
saveUninitialized: false
}));
app.use(bodyParser.urlencoded({extended:true}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.engine('html', require('ejs').renderFile);
app.use(express.static('public'));
var authRoutes = require('./routes/auth.js');
var catRoutes = require('./routes/cats.js');
app.use(authRoutes);
app.use(catRoutes);
Why is my middleware being bypassed? Please ask for additional code if it's needed.
Edit1: Updated to provide more information.
I solved the problem. I just forgot to call req.isAuthenticated in my middleware. I had it as:
function isAuthenticated(req,res,next) {
req.isAuthenticated ? next() : res.redirect('/login');
}
Whereas it should have been req.isAuthenticated().
Related
I'm trying to create a schema for a user authentication system but keep getting the above error message. I've created two new pages with the following code:
Users.js
var mongoose = require ('mongoose');
var crypto = require ('crypto');
var jwt = require('jsonwebtoken');
var userSchema = new mongoose.Schema({
email:{
type: String,
unique: true,
required: true
},
name: {
type: String,
required: true
},
hash: String,
salt: String
});
userSchema.methods.setPassword = function(password){
this.salt = crypto.randomBytes(16).toString('hex');
this.hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
};
//when the setPassword method is called and supplied with a password, the salt and hash will be generated
//for users and added to the model instance - password is never saved anywhere, and not even stored in memory
userSchema.methods.validPassword = function(password){
var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
return this.hash === hash;
};
userSchema.methods.generateJwt = function(){
var expiry = new Date();
expiry.setDate(expiry.getDate() + 7);
return jwt.sign({
_id: this._id,
email: this.email,
name: this.name,
exp: parseInt(expiry.getTime() / 1000),
}, process.env.JWT_SECRET);
};
/*var User = mongoose.model('user');
var user = new User();
user.name = "User's name";
user.email = "test#example.com";
user.setPassword("myPassword");
user.save();*/
authentication.js
var passport = require('passport');
var mongoose = require('mongoose');
var User = mongoose.model('User');
var sendJSONreponse = function(res, status, content) {
res.status(status);
res.json(content);
};
//register controller for the API
module.exports.register = function(req, res){
if(!req.body.name || !req.body.email || !req.body.password){
sendJSONreponse(res, 400, {
"message": "All fields required"
});
return;
}
var user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.setPassword(req.body.password);
user.save(function(err) {
var token;
if (err){
sendJSONreponse(res, 404, err);
} else{
token = user.generateJwt();
sendJSONreponse(res, 200, {
"token" : token
});
}
});
};
//Login controller for the API
module.exports.login = function(req, res) {
if(!req.body.email || !req.body.password){
sendJSONreponse (res, 400, {
"message" : "All fields required"
});
return;
}
passport.authenticate('local', function(err, user, info){
var token;
if (err){
sendJSONreponse(res, 404, err);
return;
}
if(user){
token = user.generateJwt();
sendJSONreponse(res, 200, {
"token" : token
});
} else {
sendJSONreponse(res, 401, info);
}
}) (req, res);
};
module.exports = router;
app.js This is some of the code which relates to the above
require('dotenv');
var express = require('express');
var createError = require('http-errors');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var bodyParser = require('body-parser');
var uglifyJS = require("uglify-js");
var fs = require ('fs');
var passport = require('passport');
//require('./app_api/models/blogModel');
require('./app_api/models/db');
require('./app_api/config/passport');
var routesApi = require('./app_api/routes/index');
var mongoose = require("mongoose");
var mongoDB = "mongodb://**********************************;
mongoose.Promise = global.Promise;
mongoose.connect(mongoDB, {useNewUrlParser: true, useUnifiedTopology: true})
.then(() => console.log('connection successful'))
.catch((err) => console.log(err));
/*BRING IN SCHEMAS AND MODELS*/
require('./users');
var app = express();
app.use(bodyParser.json());
app.use(express.static('public'));
app.use(bodyParser.urlencoded({
extended: true
}));
// view engine setup
app.set('views', path.join(__dirname, 'app_server', 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'app_client')));
app.use(passport.initialize());
app.use('/api', routesApi);
//make db accessible to router
// app.use(function(req, res, next){
// req.db=db;
// next();
// });
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// catch unauthorised errors
app.use(function (err, req, res, next){
if (err.name === 'UnauthorizedError'){
res.status(401);
res.json({"message" : err.name + ": " + err.message});
}
});
module.exports = app;
I've been following a textbook and the formatting etc. is correct; I just don't know where the error is coming from.
Thank you in advance!
At the bottom of Users you need to declare the model, using mongoose.model('Users',userSchema); also export it, you then interact with the model, schema is more of a declaration (details), the model is the implementation providing the functionality you're requiring.
You actually were pretty close, you needed to add the schema argument to the model.
I'm using passport with nodejs, express and EJS. I've created a authentication form but when I want to submit the server never responds and then resets the connection without any error message.
Here my server.js
var express = require("express");
var MongoClient = require("mongodb");
var bodyParser = require('body-parser')
var cons = require('consolidate');
var octicons = require("octicons");
var app = express();
var url = process.env.URL || "mongodb://localhost:27017/";
var dbName = process.env.DBNAME || "blog";
var port = process.env.PORT || 8000;
var routes = require("./routes");
var session = require('express-session')
var compte = require('./models/compte');
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
require('./config/passport')(passport);
app.engine('html', cons.pug);
app.set('view engine', 'html');
app.set('views', __dirname + '/views')
app.use(express.static(__dirname + '/assets'));
app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser());
app.use(session({ secret: 'simonahalepnumberone' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
MongoClient.connect(url, function(err, client) {
if(err) throw err;
routes(app, passport);
app.client = client;
app.db = client.db(dbName);
app.listen(port, function() {
console.log("now listening on http://localhost:" + port)
});
});
module.exports = app;
My index.js (which contains routes)
var posts = require("./posts");
module.exports = function(app, passport) {
function convertDate(dateString) {
var date = new Date(dateString);
return date.getDate()+"/"+date.getMonth()+"/"+date.getFullYear();
}
app.get("/", function(req, res) {
app.db.collection("articles").find({}).sort({date: 1}).toArray(function(err, result){
if(err) throw err;
result = result.reverse();
for(i = 0; i < result.length; ++i){
result[i].article = result[i].article.substr(0,75);
result[i].date = convertDate(result[i].date);
}
res.render("pages/index.ejs", {"articles": result})
});
});
app.get('/connexion', function (req, res, next) {
res.render("pages/connexion.ejs", { message: req.flash('connexionMessage') });
});
app.post('/connexion', passport.authenticate('local-login', {
successRedirect : '/',
failureRedirect : '/connexion',
failureFlash : true
}));
app.get('/deconnexion', function(req, res) {
req.logout();
res.redirect('/');
});
app.get('*', function(req, res){
res.render("pages/erreur404.ejs");
});
// Register posts endpoint
posts(app);
}
My passport.js
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/compte');
module.exports = function(passport) {
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-login', new LocalStrategy({
usernameField : 'pseudo',
passwordField : 'password',
passReqToCallback : true
},
function(req, pseudo, password, done) {
User.findOne({ 'local.pseudo' : pseudo }, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, req.flash('connexionMessage', 'Erreur dans le pseudo.'));
if (!user.validPassword(password))
return done(null, false, req.flash('connexionMessage', 'Erreur dans le mot de passe'));
return done(null, user);
});
}));
};
And my model for the user account
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var compteSchema = mongoose.Schema({
local : {
pseudo : String,
password : String,
}
});
compteSchema.methods.genererHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
compteSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
module.exports = mongoose.model('utilisateur', compteSchema);
I've follow this tutorial so I don't understand why it's not working
link
I am trying to generate token while logging in locally. Let's say I am normal user and want to sign in. Will token get generated while signing in? and how? Need guidance. Thanks
As I am using mongodb I require my users schema model in my routes code.Here is my routes code user.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/schema');
var Verify = require('./verify');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username,email: req.body.email, phone:req.body.phone }),req.body.password,
function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
When you look at the code you will notice a verify variable.It is nothing but verification that is user is registered or not.If user registered then user will allow for login.After login user will get a successfull response along with token.So here is my veirfy code verify.js
var User=require('../models/schema');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('../config.js');
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, {
expiresIn: 3600
});
};
exports.verifyOrdinaryUser = function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secretKey, function (err, decoded) {
if (err) {
var err = new Error('You are not authenticated!');
err.status = 401;
return next(err);
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
var err = new Error('No token provided!');
err.status = 403;
return next(err);
}
};
If you observe the code there is a variable like config this is nothing but connection to my mongodb.Here is the code config.js
module.exports = {
'secretKey': '12345-67890-09876-54321',
'mongoUrl' : 'mongodb://localhost:27017/conFusion'
}
And the user schema is here schema.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var User= new Schema({
username:{
type:String,
required:true,
unique:true
},
email:{
type:String,
required:true,
unique:true
},
phone:{
type:Number,
required:true,
unique:true
},
password:{
type:String
}
});
User.plugin(passportLocalMongoose);
module.exports = mongoose.model('User',User);
And finally server code app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var config = require('./config');
mongoose.connect(config.mongoUrl);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log("Connected correctly to server");
});
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
var User = require('./models/schema');
app.use(passport.initialize());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(3000,function(){
console.log("Server Listening on 3000");
});
module.exports = app;
project structure must be as per my code
+app.js
+config.js
+routes(directory)
++user.js
++verify.js
+models(directory)
++schema.js
run the code node app.js
When you want to register use http://localhost:3000/users/register
and for login use http://localhost:3000/users/login
I'm currently trying to get a node.js/express tutorial working (from Express in Action), but haven't been able to access a mongoose model properly. I call the module in a var called "User" I keep getting the error that "User.find is not a function."
Here is the models/user.js file:
var
bcrypt = require("bcrypt-nodejs"),
mongoose = require("mongoose"),
SALT_FACTOR = 10
;
var noop = function() {};
var userSchema = mongoose.Schema({
displayName: String,
bio: String
});
userSchema.pre("save", function(done) {
var user = this;
if (!user.isModified("password")) {
return done();
}
bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) { return done(err); }
bcrypt.hash(user.password, salt, noop, function(err, hashedPassword) {
if (err) { return done(err); }
user.password = hashedPassword;
done();
});
});
});
userSchema.methods.checkPassword = function(guess, done) {
bcrypt.compare(guess, this.password, function(err, isMatch) {
done(err, isMatch);
});
};
userSchema.methods.name = function() {
return this.displayName || this.username;
};
var User = mongoose.model("User", userSchema);
module.exports = User;
Here is the routes.js file calling it:
var
express = require("express"),
mongoose = require("mongoose"),
flash = require("connect-flash"),
passport = require("passport"),
router = express.Router()
;
var User = ("./models/user");
router.use(function(req, res, next){
res.locals.currentUser = req.user;
res.locals.errors = req.flash("error");
res.locals.infos = req.flash("info");
next();
});
router.get("/", function(req, res, next) {
User.find({}, function(err, users) {
assert.equal(err, null);
res.json(users);
});
});
/*
Original route, also doesn't work
router.get("/", function(req, res, next) {
User.find()
.sort({ createdAt: "descending" })
.exec(function(err, users) {
if (err) { return next(err); }
res.render("index", { users: users });
});
});
*/
module.exports = router;
Lastly here's the index.js file, in case it's relevant
var
http = require("http"),
path = require("path"),
express = require("express"),
flash = require("connect-flash"),
session = require("express-session"),
cookieParser = require("cookie-parser"),
logger = require("morgan"),
liquid = require("shopify-liquid"),
bodyParser = require("body-parser"),
mongoose = require('mongoose')
;
var routes = require('./routes');
var app = express();
mongoose.connect('mongodb://localhost:27017/test');
app.set("port", process.env.PORT || 3000);
var engine = liquid({
root: __dirname, // for layouts and partials
extname: '.liquid'
});
app.engine('liquid', engine.express());
app.set('views', ['./views', './views/partials', './views/layouts']);
app.set('view engine', 'liquid');
var assetsPath = path.resolve(__dirname, "assets");
app.use("/assets", express.static(assetsPath));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
secret: "TKRv0IJs=HYqrvagQ#&!F!%V]Ww/4KiVs$s,<<MX",
resave: true,
saveUninitialized: true
}));
app.use(flash());
app.use(routes);
app.use(logger("dev"));
app.use(function(request, response) {
response.status(404).render("404");
});
http.createServer(app).listen(3000, function(){
console.log('App skeleton started on port 3000.');
});
I've tried the solutions suggested from all similar questions but had no luck.
I am trying to create a sign up where the user if already existing in the db is logged into the system, or else a new user is created in the system.
So far I have come up with the following code.
//filename passport-config
var config = require('./config');
var passport = require('passport');
var User = require('./models/user');
var LocalStrategy = require('passport-local').Strategy;
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
};
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
}
// As with any middleware it is quintessential to call next()
// if the user is authenticated
var isAuthenticated = function (req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
passport.use('signup', new LocalStrategy({
passReqToCallback : true
},
function(req, email, password, done) {
findOrCreateUser = function(){
// find a user in Mongo with provided email
User.findOne({'email':email},function(err, user) {
// In case of any error return
if (err){
console.log('Error in SignUp: '+err);
return done(err);
}
// already exists
if (user) {
User.findOne({ 'email' : email },
function(err, user) {
if (!user){
console.log('User Not Found with email '+email);
return done(null, false);
}
// User exists but wrong password, log the error
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null,false);
}
});
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.email = email;
newUser.password = createHash(password);
// save the user
newUser.save(function(err) {
if (err){
console.log('Error in Saving user: '+err);
throw err;
}
console.log('User Registration succesful');
return done(null, newUser);
});
}
});
};
// Delay the execution of findOrCreateUser and execute
// the method in the next tick of the event loop
process.nextTick(findOrCreateUser);
})
);
my router
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/timeslot',
failureRedirect: '/'
}));
my server.js file
var express = require('express');
var bodyParser = require('body-parser');
var leisure = require('leisure');
var cors = require('cors');
var passport = require('passport');
var config = require('./config');
var passportConfig = require('./passport-config');
var session = require('express-session')
var expressHbs = require('express-handlebars');
var mediaTypes = [
{ contentType: 'application/hal+json' },
{ contentType: 'application/json' },
{ contentType: 'text/html' }
];
var app = express();
/*Handlebars */
app.engine('handlebars', expressHbs({layout: false}) );
app.set('view engine', 'handlebars');
app.use(express.static(__dirname + '/assets'));
app.use(cors(config.settings.cors));
app.use(bodyParser());
app.use(leisure.accept(mediaTypes));
/*sessions */
app.use(session({
secret: 'keyboardSFS23432##!#!#at'
}));
app.use(passport.initialize());
app.use(passport.session());
var routes = require('./routes');
app.use('/', routes.router);
function start () {
var port = process.env.PORT || 3000;
app.listen(port);
console.log('Appoints service started on port ' + port);
}
exports.app = app;
exports.start = start;
The signup route doesn't work at all and I am pretty confused on how to debug this, any suggestions will be appreciated.
Have a look at the excellent article at
http://scotch.io/tutorials/javascript/easy-node-authentication-setup-and-local
and the sample code at
https://github.com/scotch-io/easy-node-authentication (with MongoDB), or
https://github.com/tobilg/easy-node-authentication-redis (with Redis as backend)