I have been trying to add authentication feature to my angular app using express and mongo and I am getting the following error on line app.js 9:1:
"Schema hasn't been registered for model "User""
'Use mongoose.model(name, schema)',
name: 'MissingSchemaError'
Following is my app.js:
require('dotenv').config();
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var passport = require('passport');
require('./app_server/models/db');
require('./app_server/config/passport'); ----> This line is the one thats throwing the error
var indexRouter = require('./app_server/routes/index');
var usersRouter = require('./app_server/routes/users');
var app = express();
// 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(passport.initialize());
app.use('/', indexRouter);
app.use('/users', usersRouter);
Following is my passport.js:
var passport = require('passport');
var LocalStratergy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = mongoose.model('User'); ---> Probably the culprit
passport.use(new LocalStratergy({usernameField: 'email'},
function(username, password, done){
User.findOne({email: username}, function(err, user){
if (err) { return done(err); }
if (!user) {
return done(null, false, {
message: 'Incorrect Email.'
});
}
if (!user.validPassword(password)) {
return done(null, false, {
message: 'Incorrect Password.'
});
}
return done(null, user);
});
}
));
Following is my 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
},
fullname: {
type: String,
require: true
},
hash: String,
salt: String
});
Following is my db.js:
var mongoose = require('Mongoose');
var dbURI = "mongodb://localhost:27017/buddhafinds";
mongoose.connect(dbURI);
//Related functions and logs go here
require('./users');
I have been struggling with this since morning. Any help would be much appreciated. Thank you.
in your passport.js file you create a model without a schema
var User = mongoose.model('User');
try to assign the model to schema in your users.js file and export it from there
exports.User = mongoose.model('User', userSchema)
then just require User in any file you want
Related
I am trying to use Mongoose's example for defining models in a separate document from their schemas (whilst having multiple databases).
Mongoose's Docs example for User.js:
const userSchema = require('./userSchema');
module.exports = conn => {
conn.model('User', userSchema);
};
However, I am getting errors
(TypeError: users.model is not a function)
that I suspect come from the database promise that mongoose.createConnection(...)..
The structure is as followed
-models
-user.js
-schemas
-userSchema.js
-app.js
I have cut information that I don't think is apart of the problem (noted ...) but let me know if I need to include anything else.
App.js:
...
var cookieParser = require('cookie-parser');
var session = require('express-session');
var mongoose = require('mongoose');
var logger = require('morgan');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var indexRouter = require('./routes/index');
var generatorRouter = require('./routes/generator');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, 'public')));
// connect databases
var users = mongoose.createConnection('mongodb://localhost:27017/users', {useNewUrlParser: true, useUnifiedTopology: true})
.then(function() {
console.log('usersDB connected')
}).catch(err => console.log(err))
var userData = mongoose.createConnection('mongodb://localhost:27017/userData', {useNewUrlParser: true, useUnifiedTopology: true})
.then(() => console.log('userDataDB connected'))
.catch(err => console.log(err))
app.set('trust proxy', 1)
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session({
secret: shhhhh,
resave: false,
saveUninitialized: true
}));
//set up passport
app.use(passport.initialize());
app.use(passport.session());
var User = require('./models/user')(users);
app.use('/', indexRouter);
app.use('/g', generatorRouter);
app.use('/users', usersRouter);
passport.use(
new LocalStrategy(function(username, password, done) {
console.log(User);
User.findOne({
username: username
}, function(err, user) {
if (err) return done(err);
if (!user) return done(null, false);
if (!user.authenticate(password)) return done(null, false);
return done(null, user);
});
})
);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
...
module.exports = app;
user.js
var userSchema = require('../schemas/userSchema');
module.exports = users => {
users.model('User', userSchema);
};
userSchema.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt')
var userSchema = new mongoose.Schema({
"email": {
type: String,
required: true
},
"username": {
type: String,
required: true
},
"password": {
type: String,
required: true
},
"date": {
type: Date,
default: Date.now
},
})
//generate hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8));
};
// password checker
userSchema.methods.authenticate = function(password) {
return bcrypt.compareSync(password, this.password);
};
module.exports = userSchema;
I've also tried using User(users) and User(await users) but neither works for trying to pass the database into the User function.
your user.js is incorrect. You cannot use users.model('User', userSchema);
it should be like this
var userSchema = require('../schemas/userSchema');
var mongoose = require('mongoose');
module.exports = () => {
mongoose.model('User', userSchema);
};
i think the problem is in user.js file, the model function comes from mongoose so you need to create instance of mongoose and use it to create the model by .model()
so the rewrite of the code will be something like this
var mongoose = require('mongoose');
var userSchema = require('../schemas/userSchema');
module.exports = users => {
mongoose.model('User', userSchema);
};
i hope it works
Below is the Code that i'm working on but i'm getting errors while executing.
Please help me in creating routes for both login and register forms which are on the same page.
When I'm submitting the registration form with this code, I'm getting an error which says "Bad request"
var express = require ('express');
var app = express();
var path= require('path');
var bodyParser = require('body-parser');
var mongoose = require("mongoose");
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport();
var smtpTransport = require('nodemailer-smtp-transport');
var passport = require('passport');
var LocalStrategy = require('passport-local');
var passportLocalMongoose = require('passport-local-mongoose');
var User = require('./models/user');
app.set('port', process.env.PORT || 3000);
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
app.use(express.static(path.join(__dirname, 'public')));
app.set("view engine", "ejs");
app.use(require('express-session')({
secret: 'Working on enroll Medicare',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
mongoose.connect("mongodb://localhost/registration");
app.post('/login-register.html', function(req,res)
{
var username = req.body.usernameregister;
var email = req.body.emailregister;
var password1 = req.body.password1register;
var password2 = req.body.password2register;
password1, password2: password2}
User.register(new User({username: username, email: email}), password1, function(err, user){
if(err){
console.log(err);
return res.render('error');
}
passport.authenticate('local')(req, res, function(){
res.redirect("/secret");
});
});
});
login page
app.post("/login-register.html", passport.authenticate('local', {
succesRedirect: "/secret",
failureRedirect: "/error"
}), function(req, res){ });
I think you may have multiple problems here. Here are a few things to check:
You have passport.use(new LocalStrategy(User.authenticate()));. I don't know what User.authenticate() returns, but it should return a function with the arguments function(username, password, done) {...}
It looks like you're using email as the username. You need to add usernameField to the strategy options: new LocalStrategy({usernameField: 'email'}, function(email, password, done){...})
I've also found it really helpful to use a custom callback in the passport.authenticate function to see if the returned error provides any more information about the problem: passport.authenticate('local', function(err, user, info) {console.log(err, user, info)})
I am trying to implement login through OAuth 2.0, however I can't make my sessions persist, it seems right after a users has been authenticated their session is gone. Also, the app seems to get stuck in routes/bnetauth.js at the redirect in the callback function.
These are the files where I use passport
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
//TOOLS
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session'); //Persistant sessions
var passport = require('passport');
//REQUIRE MODELS
require('./models/News');
require('./models/Application');
//REQUIRE ROUTES
var bnetauth = require('./routes/bnetauth')(passport);
var api = require('./routes/api');
var public = require('./routes/public');
var admin = require('./routes/admin');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/karatechop');
require('./config/passport')(passport);
var app = express();
app.use(express.static('views'));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 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')));
app.use(session({
secret: 'ilovescotchscotchyscotchscotch', // session secret
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
//Use Routes
app.use('/auth', bnetauth)
app.use('/api', api);
app.use('/admin', admin);
app.use('/', public);
// 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);
});
module.exports = app;
routes/bnetauth.js (Logging in through battle.net, hence the bnetauth name)
var express = require('express');
var router = express.Router();
module.exports = function(passport) {
router.get('/bnet',
passport.authenticate('bnet'));
router.get('/bnet/callback',
passport.authenticate('bnet', {
failureRedirect: '/' }),
function(req, res, next){
console.log('Authenticated: ' + req.isAuthenticated())
####THIS IS WHERE IT GETS STUCK####
res.redirect('https://localhost:3000/');
});
config/passport.js
var BnetStrategy = require('passport-bnet').Strategy;
var BNET_ID = 'hidden'
var BNET_SECRET = 'hidden'
var User = require('../models/user')
// expose this function to our app using module.exports
module.exports = function(passport) {
console.log('Entering passport')
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
console.log('Serializing')
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log('Deserializing')
done(err, user);
});
});
passport.use(new BnetStrategy({
clientID: BNET_ID,
clientSecret: BNET_SECRET,
region: 'eu',
callbackURL: "https://localhost:3000/auth/bnet/callback"
}, function(accessToken, refreshToken, profile, done) {
console.log(profile)
console.log(accessToken)
User.findOne({id: profile.id}, function(err, user){
console.log("Trying!")
if(err)
return done(err);
if(user) {
return done(null, user);
} else {
var newUser = new User();
newUser.id = profile.id,
newUser.token = accessToken,
newUser.battle_tag = profile.battletag
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
}));
};
return router;
}
I found the solution to my problem!
The problem was in my serialize and deserialize functions in config/passport.js
On my user model, I had two forms of ids.
The _id applied by mongo
The id that I save from the users object passed back to me from battle.net (this is the ID of the user on battle.net).
In serialize, the id that would be used when serializing the user to the session would be the battle.net id (since I was calling user.id and not user._id
Then, in the deserialize when extracting data from the user object, I was using mongo's findById function, which uses the ._id (which is totally different from .id in my user's object, hence it returned 'undefined'.
Changing the .id to ._id in the serialize function solved my problem, and sessions are now working and are persistent.
I can't resolve an issue with mongoose throwing error
throw new mongoose.Error.MissingSchemaError(name);
^
MissingSchemaError: Schema hasn't been registered for model "Appointment".
Use mongoose.model(name, schema)
I included all paths, checked it according to my another Schemas and everything seems alright. Am I missing something?
EXPRESS.JS:
var config = require('./config'),
express = require('express'),
morgan = require('morgan'),
compress = require('compression'),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
session = require('express-session');
module.exports = function() {
var app = express();
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
} else if(process.env.NODE_ENV === 'production') {
app.use(compress());
}
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(session({
saveUninitialized: true,
resave: true,
secret: 'config.sessionSecret'
}));
app.set('views', './app/views');
app.set('view engine', 'ejs');
require('../app/routes/index.server.routes')(app);
require('../app/routes/users.server.routes')(app);
require('../app/routes/appointment.server.routes')(app);
app.use(express.static('./public'));
return app;
};
APPOINTMENT.SERVER.MODEL.JS:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var AppointmentSchema = new Schema({
UserID: {
type: Schema.ObjectId,
ref: User,
private: true
},
time: {
type: String,
get: function(){
for (var i in Schedule.freeTime){
if (i === this.time) {
return this.time
}
}
}
}
});
mongoose.model('Appointment', AppointmentSchema);
AppointmentSchema.set('toJSON', {getters: true});
APPOINTMENTS.SERVER.CONTROLLER.JS:
var Appointment = require('mongoose').model('Appointment'),
User = require('./user.server.controller');
exports.create = function(req,res,next) {
var appointment = new Appointment(req.body);
appointment.UserID = User;
appointment.save(function (err) {
if (err){
return next(err);
} else{
res.json(appointment);
}
});
};
APPOINTMENT.SERVER.ROUTES.JS:
var appointments = require('../../app/controllers/appointment.server.controller');
module.exports = function(app) {
app.route('/appointment').post(appointments.create);
};
Error seems to say that I didn't create Appointment Schema, which I did in APPOINTMENT.SERVER.MODEL.JS:
Nevermind, seems like I messed up with mongoose config itself... Problem solved!
Hi i am developing nodejs application with express and mongodb.So i must define mongoose and schema in my all routing js to use mongo and schema. I want to define them only ones. I am new at node.js so please be patient. My project structure:
My route.js is shown below:
var routes = function (app) {
app.locals.error=null;
app.get('/login', function (req, res) {
return res.render(__dirname + "/views/login", {
title: 'Giriş',
stylesheet: 'login'
});
});
var mongoose = require('mongoose');
mongoose.connect("mongodb://localhost/fuatblog");
var UserSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
age: Number
}),
Users = mongoose.model('Users', UserSchema);
app.post('/sessions', function (req, res) {
console.log(req.body.login.email);
console.log(req.body.login.password);
console.log(req.body.login.rememberMe);
Users.find({
email: req.body.login.email,
password: req.body.login.password
}, function (err, docs) {
if (! docs.length) {
// no results...
console.log('User Not Found');
res.status(400);
return res.render(__dirname + "/views/login", {
title: 'Giriş',
stylesheet: 'login',
error: 'Kullanıcı adı veya şifre yanlış'
});
}
console.log('User found');
req.session.email = docs[0].email;
console.log(req.session.email);
return res.redirect('/Management');
});
});
};
module.exports = routes;
And my server.js(app.js)
/**
* Module dependencies.
*/
////Mongoose eklendi
var express = require('express'),
mongoose= require('mongoose');
var http = require('http');
var path = require('path');
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
////Cookie için eklendi.
app.use(express.cookieParser());
////Session desteği için eklendi
app.use(express.session({secret: 'asdfsdfsafasdfasdfasdf'}));
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
////Put ve Delete mothodları için
app.use(express.methodOverride());
////Requeestleri ayrıştırmak için kullanılıyor
app.use(express.bodyParser());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
////Helpers
//require('./apps/helpers')(app);
//Routes
require('./apps/authentication/routes')(app)
require('./apps/blog/routes')(app)
require('./apps/management/routes')(app)
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
I'm going to assume that you meant that you want to define the Schema only ONCE.
What I like to do is to initialize all the models that I'm going to use when the server starts and the mongodb connection is established.
An ideal directory structure would be something like this:
mongodb
--schemas
----user.js
--models.js
You would put your schemas inside the schema folder, such as your User model:
(user.js)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports = function() {
var UserSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
age: Number
});
mongoose.model("User", UserSchema);
};
In models.js, you would have code that initializes each schema model in the schemas directory.
(models.js)
exports.initialize = function() {
require("fs").readdirSync(__dirname + "/schemas").forEach(function(file) {
require('./schemas/' + file)();
});
};
In your app.js file, you would do this call to initialize all your schemas AFTER you establish your connection to mongoose:
require($pathToYourModelsJsFile).initialize();
After this, you are all set to use your models! All you have to do for when you want to use them is:
var mongoose = require('mongoose');
var User = mongoose.model('User');
// Do work
User.find();