I'm very new to node.
I want to apply custom authentication using passport.js to all router.
using this example. -> https://github.com/passport/express-4.x-http-bearer-example
the code below is my server/index.js.
const express = require('express');
const path = require('path');
const index = require('./routes/index.js');
const downloadRouter = require('./routes/fileDownload.js');
const app = express();
app.disable("x-powered-by");
app.use('/', express.static(path.join(__dirname, '..', 'dist')));
app.set("src", path.join(__dirname, "../src"));
var passport = require('passport');
var Strategy = require('passport-http-bearer').Strategy;
var db = require('./adminDB');
passport.use(new Strategy(
function(token, cb) {
db.users.findByToken(token, function(err, user) {
if (err) { return cb(err); }
if (!user) { return cb(null, false); }
return cb(null, user);
});
}));
// app.use('/api-test', passport.authenticate('bearer', { session: false
}), function(req, res) {
// res.json({ username: req.user.username, value:
req.user.emails[0].value });
// res.end();
// });
app.use('*', passport.authenticate('bearer', { session: false }),
function(req, res, next) {
console.log("api all before action")
if(!err) {
next();
} else {
res.status(401).end();
}
});
app.use('/download', downloadRouter);
const { PORT = 8080 } = process.env;
app.listen(PORT, () => console.log(`Listening on port ${PORT}`));
// export default app;
what I want to ask is this part.
The annotated api-test parts handles authenication very well. However, the "app.use(*)" part does not handle it. console.log is also not working. Returns 200, regardless of the certification procedure, outputting the original screen(index.html).
How do I authenticate across all my routers and get all of my screens back to their original output?
I leave an answer because there may be someone in a similar situation.
app.use('*', passport.authenticate('bearer', { session: false }), function(req, res, next) {
next();
});
put this code, upper then router code.
Related
Really stuck on the same issue for much time. Tried many things but all to no use. Please help.
The register module works fine but the login doesn't. It returns 404 error upon hitting submit button. Attached are the appropriate code documents.
The login module is supposed to redirect to contactlist upon successful authentication.
Thank you very much!.
app.js
let createError = require('http-errors');
let express = require('express');
let path = require('path');
let cookieParser = require('cookie-parser');
let logger = require('morgan');
var bodyParser = require('body-parser');
let Login = require('../models/login')
let passport = require('passport');
let LocalStrategy = require('passport-local').Strategy;
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); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
//database setup
let mongoose = require('mongoose');
let DB = require('./db');
//point mongoose to the db URI
mongoose.connect(DB.URI);
let mongoDB = mongoose.connection;
mongoDB.on('error',console.error.bind(console,'Connection Error in Mongo'));
mongoDB.once('open',()=>{
console.log("Connected to MongoDB");
})
let indexRouter = require('../routes/index');
let usersRouter = require('../routes/users');
let loginRouter = require('../routes/login');
let authRouter = require('../routes/auth');
const exp = require('constants');
let app = express();
// view engine setup
app.set('views', path.join(__dirname, '../views'));
app.set('view engine', 'ejs');
app.use(bodyParser.json());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(require('express-session')({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}));
app.use(express.static(path.join(__dirname, '../../public')));
app.use(express.static(path.join(__dirname,'../../node_modules')));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/login', loginRouter);
app.use('/', authRouter);
// passport config
passport.serializeUser(Login.serializeUser());
passport.deserializeUser(Login.deserializeUser());
// 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',{ title: 'error' });
});
module.exports = app;
auth.js
let express = require('express');
let router = express.Router();
let passport = require('passport');
let user = require('../models/user');
router.post('/register',(req,res,next)=>{
user.register(new user({
username:req.body.username,
}),
req.body.password,(err, newUser) =>{
if(err){
return res.redirect('/login/register')
}
else{
req.login(newUser,(err) => {
res.redirect('/login/contactlist')
})
}
}
)
});
router.post('/', passport.authenticate('local', { failureRedirect: '/login/contactlist' }),
function(req, res) {
res.redirect('/login/contactlist');
});
module.exports = router;
login.js
let express = require('express');
let router = express.Router();
let passport = require('passport');
/* GET index page. */
let Login = require('../models/login')
let Contact = require('../models/contact')
router.get('/', function(req, res, next) {
Login.find((err,loginList)=>{
if(err){
return console.error(err);
}
else {
//console.log(loginList);
res.render('login/login', { title: 'Login',loginList: loginList,user: req.user });
}
});
});
router.get('/register', function(req, res, next) {
res.render('login/register')
});
/* GET contactlist page. */
router.get('/contactlist', function(req, res, next) {
Contact.find((err,contactList)=>{
if(err){
return console.error(err);
}
else {
res.render('login/contactlist', { title: 'contactlist',contactList: contactList });
}
});
});
/* GET update page. */
router.get('/update/:id', function(req, res, next) {
let id = req.params.id;
Contact.findById(id, (err, contactToEdit) => {
if(err)
{
console.log(err);
res.end(err);
}
else
{
//show the edit view
res.render('login/update', {title: 'Update', contact:contactToEdit })
}
});
});
router.get('/delete/:id', function(req, res, next) {
let id = req.params.id;
Contact.remove({_id: id}, (err) => {
if(err)
{
console.log(err);
res.end(err);
}
else
{
// refresh the contacts list
res.redirect('/login/contactlist');
}
});
});
/* POST update page. */
router.post('/update/:id', function(req, res, next) {
let id = req.params.id
let newContact = Contact({
"_id":id,
"email":req.body.email,
"number": req.body.number,
"name":req.body.name
});
Contact.updateOne({_id: id},newContact,(err)=>{
console.log(newContact);
if(err){
console.log(err);
res.end(err);
}
else{
console.log(id)
console.log("POST update");
res.redirect('/login');
}
});
});
/* POST contactlist page. */
router.post('/contactlist', function(req, res, next) {
res.render('login/contactlist', { title: 'contactlist' });
});
module.exports = router;
I just realized an app I have been working on no longer works when I sign in to the application. After I sign in I get a blank page with
this.sessionModel.find is not a function printed at the top with a 500 error in the console
I am deathly afraid there is something wrong with the packages I am using. Has anyone ever experienced this problem before? I'll add some code snippets below, let me know if I need to provide more info thank you so much in advance. Here is how I am setting up the server:
const path = require('path')
const express = require('express')
const morgan = require('morgan')
const bodyParser = require('body-parser')
const compression = require('compression')
const session = require('express-session')
const passport = require('passport')
const SequelizeStore = require('connect-session-sequelize')(session.Store)
const db = require('./db')
const sessionStore = new SequelizeStore({db})
const PORT = process.env.PORT || 8080
const sslRedirect = require('heroku-ssl-redirect')
const app = express()
module.exports = app
/**
this file is where we import middleware, route the routes, sync the db, and start the server.
*/
if (process.env.NODE_ENV !== 'production') require('../secrets')
// passport registration
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) =>
db.models.user.findById(id)
.then(user => done(null, user))
.catch(done))
const createApp = () => {
// logging middleware
app.use(morgan('dev'))
// body parsing middleware
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
// compression middleware
app.use(compression())
// session middleware with passport
app.use(session({
secret: process.env.SESSION_SECRET || 'nothing',
store: sessionStore,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
// auth and api routes
app.use(sslRedirect())
app.use('/auth', require('./auth'))
app.use('/api', require('./api'))
// static file-serving middleware
app.use(express.static(path.join(__dirname, '..', 'public')))
// any remaining requests with an extension (.js, .css, etc.) send 404
app.use((req, res, next) => {
if (path.extname(req.path).length) {
const err = new Error('Not found')
err.status = 404
next(err)
} else {
next()
}
})
// sends index.html
app.use('*', (req, res) => {
res.sendFile(path.join(__dirname, '..', 'public/index.html'))
})
// error handling endware
app.use((err, req, res, next) => {
console.error(err)
console.error(err.stack)
res.status(err.status || 500).send(err.message || 'Internal server error.')
})
}
const startListening = () => {
// start listening (and create a 'server' object representing our server)
const server = app.listen(PORT, () => console.log(`Serving on port ${PORT}`))
}
const syncDb = () => db.sync()
// This evaluates as true when this file is run directly from the command line,
// i.e. when we say 'node server/index.js' (or 'nodemon server/index.js', or 'nodemon server', etc)
// It will evaluate false when this module is required by another module - for example,
// if we wanted to require our app in a test spec
if (require.main === module) {
sessionStore.sync()
.then(syncDb)
.then(createApp)
.then(startListening)
} else {
createApp()
}
and here are my routes for logging in:
const router = require('express').Router()
const User = require('../db/models/user')
module.exports = router
//routes for login authentication
//login
router.post('/login', (req, res, next) => {
User.findOne({where: {email: req.body.email}})
.then(user => {
if (!user) {
res.status(401).send('User not found')
} else if (!user.correctPassword(req.body.password)) {
res.status(401).send('Incorrect password')
} else {
req.login(user, err => (err ? next(err) : res.json(user)))
}
})
.catch(next)
})
//change password
router.put('/:id/resetpw', (req, res, next) => {
User.update(req.body, {
where: {
id: req.params.id
},
individualHooks: true
})
.then(([updatedRows, [updatedUser]]) => {
res.status(200).json(updatedUser)
})
.catch(next)
})
//sign up
router.post('/signup', (req, res, next) => {
User.create(req.body)
.then(user => {
req.login(user, err => (err ? next(err) : res.json(user)))
})
.catch(err => {
if (err.name === 'SequelizeUniqueConstraintError') {
res.status(401).send('User already exists')
} else {
next(err)
}
})
})
//logout
router.post('/logout', (req, res) => {
req.logout()
req.session.destroy()
res.redirect('/')
})
router.get('/me', (req, res) => {
res.json(req.user)
})
That's usually a sign of attempting to load modules defined as ES6 exports.
For example, to load the latest version of heroku-ssl-redirect in Express (as of now), one must use:
const sslRedirect = require('heroku-ssl-redirect').default;
Notice the .default at the end. Your heroku-ssl-redirect import seems to be working without it, but the latest version I installed today requires the .default otherwise throws the same error, reading in this case sslRedirect is not a function.
I cannot see the code of your models, but in this thread the same approach is used to load models when using Sequelize:
const model = require(modelPath).default(sequelize, Sequelize);
Notice the .default at the model require.
That could be the problem with your erring packages.
Problem
I am using a nodejs application with the express module. To have a structure I split the routes into a extern routes.js. I want give this route.js next to the req and res parameters some other parameters who will be needed. But I donĀ“t know how I can do it.
Index.js
const app = express();
app.use(session({
secret: uuidv4(),
resave: true,
saveUninitialized: true
}));
app.use(helmet());
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use('/', express.static(path.join(__dirname, '/site/static')));
app.use('/', routes);
routes.js
module.exports = (function() {
'use strict';
let router = require('express').Router();
router.get('/', (req, res) => {
if(!req.session || req.session.key !== loginkey) {
res.redirect('/login');
} else {
res.redirect('dashboard');
};
});
router.get('/dashboard', (req, res) => {
if(req.session && req.session.key === loginkey) {
helper.render(req, res, "sites/dashboard");
} else {
res.redirect('/');
};
});
router.get('/login', (req, res) => {
log.LogLine(3, "GET /login");
helper.render(req, res, "sites/login");
});
router.get('/logout', (req, res, next) => {
log.LogLine(3, "GET /logout");
if (req.session) {
req.session.destroy(function(err) {
if(err) {
return next(err);
} else {
return res.redirect('/');
};
});
};
});
return router;
})();
If you want to pass something along from index.js to your routes in routes.js then you can do the following.
In your routes.js, you could accept some parameters:
module.exports = function(arg1, arg2) {
let router = require('express').Router();
router.get('/', (req, res) => {
// You can now use arg1 and arg2 here
});
// ...
return router;
};
Note, you'll need to remove your IIFE to stop the function from being immediately invoked.
Then in index.js, you can invoke the function and pass in whatever you want:
app.use('/', routes('something', 'something else'));
I hope this helps.
I have some problems with the express session where I cannot retrieve my session variable that I had stored previously. Below are parts of my codes that I had written.
server.js
let express = require('express'),
path = require('path'),
bodyParser = require('body-parser'),
cors = require('cors'),
config = require('./config/database'),
expressSession = require('express-session'),
uid = require('uid-safe'),
db;
let app = express();
//Import Routes
let auth = require('./routes/auth'),
chimerListing = require('./routes/chimer-listing'),
brandListing = require('./routes/brand-listing');
//Specifies the port number
let port = process.env.PORT || 3000;
// let port = 3000;
// Express session
app.use(expressSession({
secret: "asdasd",
resave: true,
saveUninitialized: false,
cookie: {
maxAge: 36000000,
secure: false
}
}));
//CORS Middleware
app.use(cors());
//Set Static Folder
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));
//Body Parser Middleware
app.use(bodyParser.json());
//MongoDB
let MongoClient = require('mongodb').MongoClient;
MongoClient.connect(config.database, (err, database) => {
if (err) return console.log(err)
db = database;
//Start the server only the connection to database is successful
app.listen(port, () => {
console.log('Server started on port' + port);
});
});
//Make db accessbile to routers;
app.use(function(req, res, next) {
req.db = db;
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.set('Access-Control-Allow-Headers', 'Content-Type');
next();
});
//Routes
app.use('/login', auth);
app.use('/user-listing', userListing);
app.use('/brand-listing', brandListing);
//Index Route
app.get('/', (req, res) => {
res.send('Invalid Endpoint');
});
genuuid = function() {
return uid.sync(18);
};
auth.js
let express = require('express'),
router = express.Router(),
db;
//Login Router for chimer
router.post('/chimer', (req, res, next) => {
db = req.db;
// let client = req.client;
db.collection('chimeUser').find({
Username: req.body.username,
Password: req.body.password
}).toArray().then(function(docs) {
//If there is such user
if (docs.length >= 1) {
req.session.chimerId = docs[0]._id;
console.log(req.session);
req.session.save(function(err) {
// session saved
if (err)
console.log(err)
res.json({
success: true,
chimerId: docs[0]._id
//objects: docs
});
})
} else {
res.json({
success: false,
//objects: docs
})
}
});
});
//Login Router brand
router.post('/brand', (req, res, next) => {
db = req.db;
db.collection('brand').find({
Username: req.body.username,
Password: req.body.password
}).toArray().then(function(docs) {
req.session.brand = docs;
console.log(req.session.brand);
//If there is such user
if (docs.length >= 1) {
res.json({
success: true,
//objects: docs
})
} else {
res.json({
success: false,
//objects: docs
})
}
//db.close()
});
});
});
module.exports = router;
user-listing.js
let express = require('express'),
moment = require('moment'),
router = express.Router(),
// ObjectID = require('mongodb').ObjectID,
db, client;
// let applyListing = require('../models/chimer-listing');
//Retrieve All Listing
router.get('/getAllListing', (req, res, next) => {
db = req.db;
console.log(req.session)
db.collection('listing').find().toArray().then(function(listing) {
//If there is any listing
if (listing.length >= 1) {
res.json({
success: true,
results: listing
})
} else {
res.json({
success: false,
})
}
//db.close()
});
});
module.exports = router;
So in my server.js, I have three routes file which is auth, user-listing, and brand-listing.
Firstly, a user will need to login with the web application which is developed in angular2 and this will trigger the auth route. It will then check for the credentials whether does it exist in the database if it exists I will then assign an ID to req.session.chimerId so that in other routes I will be able to use this chimerId.
Next, after the user has logged in, they will then retrieve an item listing. The problem arises where I can't seem to retrieve the req.session.chimerId that I had previously saved. It will be undefined
NOTE: I tried this using Postman and the browser. In the Postman it works, I am able to retrieve back the req.session.chimerId whereas when I use the angular2 application to hit the endpoints req.session.chimerId is always null
https://github.com/jaredhanson/passport-remember-me
passport.use(new RememberMeStrategy(
function(token, done) {
Token.consume(token, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
return done(null, user);
});
},
function(user, done) {
var token = utils.generateToken(64);
Token.save(token, { userId: user.id }, function(err) {
if (err) { return done(err); }
return done(null, token);
});
}
));
post
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res, next) {
// issue a remember me cookie if the option was checked
if (!req.body.remember_me) { return next(); }
var token = utils.generateToken(64);
Token.save(token, { userId: req.user.id }, function(err) {
if (err) { return done(err); }
res.cookie('remember_me', token, { path: '/', httpOnly: true, maxAge: 604800000 }); // 7 days
return next();
});
},
function(req, res) {
res.redirect('/');
});
I'm trying to implement remember me feature (above) into my existing application but I couldn't make it. When I add RememberMeStrategy into my login.js, it throws
ReferenceError: RememberMeStrategy is not defined
error. What's missing here?
index.js
var rendering = require('../util/rendering');
var express = require('express');
var router = express.Router();
exports.home = function(req, res) {
res.render('index/index');
};
exports.userHome = function(req, res) {
res.render('index/user-home');
};
login.js
var crypto = require('crypto'),
passport = require('passport'),
passportRememberMe = require('passport-remember-me'),
passportLocal = require('passport-local'),
data = require('../models/auth')();
exports.registerPage = function (req, res) {
res.render('login/register', {username: req.flash('username')});
};
exports.registerPost = function (req, res) {
var vpw = req.body.vpw;
var pwu = req.body.pw;
var un = req.body.un;
req.flash('username', un);
if (vpw !== pwu) {
req.flash('error', 'Your passwords did not match.');
res.redirect('/register');
return;
}
req.checkBody('un', 'Please enter a valid email.').notEmpty().isEmail();
var errors = req.validationErrors();
if (errors) {
var msg = errors[0].msg;
req.flash('error', msg);
res.redirect('/register');
return;
}
var new_salt = Math.round((new Date().valueOf() * Math.random())) + '';
var pw = crypto.createHmac('sha1', new_salt).update(pwu).digest('hex');
var created = new Date().toISOString().slice(0, 19).replace('T', ' ');
new data.ApiUser({email: un, password: pw, salt: new_salt, created: created}).save().then(function (model) {
passport.authenticate('local')(req, res, function () {
res.redirect('/home');
})
}, function (err) {
req.flash('error', 'Unable to create account.');
res.redirect('/register');
});
};
exports.loginPage = function (req, res) {
res.render('login/index', {username: req.flash('username')});
};
exports.checkLogin = function (req, res, next) {
passport.authenticate('local', function (err, user, info) {
if (err || !user) {
req.flash('username', req.body.un);
req.flash('error', info.message);
return res.redirect('/login');
}
req.logIn(user, function (err) {
if (err) {
req.flash('error', info.message);
return res.redirect('/login');
}
req.flash('success', 'Welcome!');
return res.redirect('/home');
});
})(req, res, next);
};
exports.logout = function (req, res) {
req.logout();
req.flash('info', 'You are now logged out.');
res.redirect('/login');
};
routes.js
var rendering = require('./util/rendering'),
indexController = require('./controllers/index'),
loginController = require('./controllers/login');
module.exports = function (app, passport) {
// Home
app.get('/', indexController.home);
app.get('/home', ensureAuthenticated, indexController.userHome);
// Auth
app.get('/register', loginController.registerPage);
app.post('/register', loginController.registerPost);
app.get('/login', loginController.loginPage);
app.post('/login', loginController.checkLogin);
app.get('/logout', loginController.logout);
// 'rendering' can be used to format api calls (if you have an api)
// into either html or json depending on the 'Accept' request header
app.get('/apitest', function(req, res) {
rendering.render(req, res, {
'data': {
'test': {
'testsub': {
'str': 'testsub hello world'
},
'testsub2': 42
},
'test2': 'hello world'
}
});
})
// Auth Middleware
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login');
}
}
server.js
var dbConfig;
try {
// Look for dev conf for local development
dbConfig = require('./config/db.dev.conf.js');
} catch(e) {
try {
// production conf?
dbConfig = require('./config/db.conf.js');
} catch(e) {
console.log('Startup failed. No db config file found.');
return false;
}
}
var knex = require('knex')({
client: 'mysql',
connection: dbConfig
}),
express = require('express'),
bodyParser = require('body-parser'),
cookieParser = require('cookie-parser'),
cookieSession = require('cookie-session'),
serveStatic = require('serve-static'),
expressValidator = require('express-validator'),
flash = require('connect-flash'),
swig = require('swig'),
passport = require('passport'),
passportRememberMe = require('passport-remember-me'),
passportLocal = require('passport-local'),
crypto = require('crypto'),
Bookshelf = require('bookshelf'),
messages = require('./util/messages');
var app = express();
Bookshelf.mysqlAuth = Bookshelf(knex);
app.use(cookieParser('halsisiHHh445JjO0'));
app.use(cookieSession({
keys: ['key1', 'key2']
}));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(expressValidator());
app.use(passport.initialize());
app.use(passport.session());
app.use(passport.authenticate('remember-me'));
app.use(flash());
app.use(serveStatic('./public'));
//app.use(express.favicon(__dirname + '/public/images/shortcut-icon.png'));
app.use(messages());
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
require('./util/auth')(passport);
require('./routes')(app, passport);
app.listen(process.env.PORT || 3000);
console.log('Listening on port 3000');
That error is simply saying that you haven't defined the RememberMeStrategy function before calling it (you're using new but in Javascript that's just calling a function with a special variable called this). You need to require the module first, in this case:
var RememberMeStrategy = require('passport-remember-me').Strategy;
Just require it in the variable RememberMeStrategy
var RememberMeStrategy= require('passport-remember-me').Strategy;