I have been browsing the forum but I am unable to find the error in my code , it always results in false and I am not able to solve it , Please help me... Is there any other way to authenticate user instead of passport so that I can use it.I am adding more sentences as it is not allowing me to post my query,Sorry..
const http = require("http"), hostname = "127.0.0.1", port = 3000, bodyParser = require("body-parser"), mongoose = require("mongoose"), express = require("express"), passport = require("passport"), localStrategy = require("passport-local"), passportLocalMongoose = require("passport-local-mongoose"), User = require("./models/user"); app = express(); mongoose.connect("mongodb://localhost/drive", { useNewUrlParser: true }); app.set("view engine", "ejs"); app.use(express.static("public")); app.use(passport.initialize()); app.use(passport.session()); app.use( require("express-session")({ secret: "Beta tumse na ho payega", resave: false, saveUninitialized: false }) ); passport.use(new localStrategy(User.authenticate())); passport.serializeUser(User.serializeUser()); passport.deserializeUser(User.deserializeUser()); app.use(bodyParser.urlencoded({ extended: true })); const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader("Content-Type", "text/plain"); }); app.get("/", function(req, res) { res.render("index"); }); app.get("/register", function(req, res) { res.send("hello"); }); app.get("/login", function(req, res) { res.render("login"); }); app.post( "/login", passport.authenticate("local", { successRedirect: "/", failureRedirect: "/login" }), function(req, res) {} ); app.get("/logout", function(req, res) { req.logout(); res.redirect("/"); }); function isLoggedIn(req, res, next) { if (req.isAuthenticated()) { return next(); } else { console.log("Not logged"); res.redirect("/login"); } } app.get("/secret", isLoggedIn, function(req, res) { res.send("You are logged in"); }); app.post("/register", function(req, res) { if (req.body.password === req.body.cpassword) { User.register( new User({ username: req.body.username }), req.body.password, function(err, user) { if (err) console.log(err); else passport.authenticate("local")(req, res, function() { res.send("signed up"); }); } ); } else res.send("Password Mismatch"); }); //DRIVE SCHEMA //var driveSchema = mongoose.Schema({ // title: String, // created: { type: Date, default: Date.now } //}); app.listen(port, hostname, function() { console.log("Server is running at " + hostname + "/" + port); });
//./models/user.js file const mongoose = require("mongoose"), passportLocalMongoose = require("passport-local-mongoose"); var UserSchema = new mongoose.Schema({ username: String, password: String }); UserSchema.plugin(passportLocalMongoose); module.exports = mongoose.model("User", UserSchema);
I have used passport
and jwt
library, to authenticate and maintain session for the user. There is no need to maintain user session on server side.
apis/apis.js : This file has all apis end points. /login
url will authenticate user using passport and send a token to the client using jwt
const passport = require('passport')
const expRoute = require('express').Router();
let exporter = process.exporter;
expRoute.post('/login', (req, res, next) => {
passport.authenticate(
'local',
{
// successRedirect: '/',
// failureRedirect: '/login',
successFlash: 'Welcome!',
failureFlash: 'Invalid username or password.'
},
(err, user, info) => {
if (err) {
return res.status(500).json(err)
}
else if (user) {
return res.status(200).json({
token: exporter.generateToken(user)
})
}
else {
return res.status(400).json(info)
}
}
)(req, res, next);
})
expRoute.get('/view', exporter.authenticateToken, (req, res) => {
let param = req.finalTokenExtractedData
if (param && exporter.isObjectValid(param, 'tokenId', true, true)) {
let condition = {
_id: param.tokenId
}
let options = {
_id: 0,
password: 0,
__v: 0
}
process.USER.findOne(condition, options) // mongo find
.then((data) => {
res.status(200).json({
result: data,
msg: 'success'
})
})
.catch((mongoErr) => {
exporter.logNow(`USER mongo Error: ${mongoErr}`)
res.status(400).json({
msg: 'user not found'
})
})
}
else {
res.status(404).json({
msg: 'invalid token'
})
}
})
module.exports = expRoute
common/env.js: This file will initialise all connections such mongo, require few files will be used as global
process.CONFIG = require('../configs/config.json')
process.exporter = require("../lib/exporter.js")
process.dbInit = (globalName, mongoUrl, collectionName) => {
require("../models/db-init.js")(mongoUrl, collectionName)
.then((modelObj) => {
process[globalName] = modelObj // will be used as global
})
.catch((dbInitErr) => {
process.exporter.logNow(`dbInit Error: ${dbInitErr}`)
process.exit()
});
}
lib/exporter.js: This file has exporter class which consist of all major functions like mongo connection, authenticateToken, verifyPassword, etc.
const fs = require('fs'),
redis = require("redis"),
path = require("path"),
mongoose = require('mongoose'); mongoose.set('useCreateIndex', true);
const Schema = mongoose.Schema;
var bcrypt = require('bcryptjs')
var jwt = require('jsonwebtoken')
class Exporter {
mongoConnection(mongoURI, schemaObj) {
return new Promise(async (resolve, reject) => {
if (!mongoURI || typeof mongoURI == 'undefined' || mongoURI.length < 1)
return reject('invalid mongo connection url');
return resolve(mongoose.createConnection(mongoURI, { useNewUrlParser: true }))
})
}
createMongoSchema(schemaObj) {
return (new Schema(schemaObj));
}
createMongoModel(mongoDB, collectionName, newSchema) {
if (newSchema)
return mongoDB.model(collectionName, newSchema)
return mongoDB.model(collectionName)
}
authenticateToken(req, res, next) {
const bearerHeader = req.header('authorization')
if (typeof bearerHeader != 'undefined') {
const bearer = bearerHeader.split(' ')
const bearerToken = bearer[1]
jwt.verify(bearerToken, process.CONFIG.jwt.token.activated, (err, data) => {
if (err)
res.status(400).json({
msg: "Invalid token or please try to login again"
})
else {
process.exporter.getSingleHashKeysValuesFromRedis('expired_token', bearerToken)
.then((redisTokendata) => {
if (redisTokendata)
res.status(400).json({
msg: "token expired"
})
else {
req.finalTokenExtractedData = data
// if (req.originalUrl.trim() == process.logoutURL.trim())
req.jwtToken = {
token: bearerToken,
secret: process.CONFIG.jwt.token.activated
}
next()
}
})
.catch((redisTokenError) => {
process.exporter.logNow(`redis token error: ${redisTokenError}`)
res.status(400).json({
msg: "Some went wrong while checking token. Please try later."
})
})
}
})
}
else
res.status(400).json({
msg: "invalid token"
})
}
generateToken(data) {
let expiry = new Date();
// expiry.setDate(expiry.getDate() + 7)
expiry.setMinutes(expiry.getMinutes() + 5)
return jwt.sign({
tokenId: data._id,
exp: parseInt(expiry.getTime() / 1000),
}, process.CONFIG.jwt.token.activated)
}
createPassword(password) {
return new Promise((resolve, reject) => {
if (typeof password == 'undefined' && password == '')
return reject('password empty')
bcrypt.hash(password, 10, async (bErr, hash) => {
if (bErr)
reject(bErr)
else
resolve(hash)
})
})
}
verifyPassword(enteredPassword, savePassword) {
return bcrypt.compareSync(enteredPassword, savePassword)
}
}
module.exports = (new Exporter());
index.js: This is file which you will execute node index.js
.
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const passport = require('passport');
require('./common/env')
require('./configs/passport')
const app = express()
const cors = require('cors')
app.use(cors());
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true}))
app.use(passport.initialize())
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
let apis = require('./apis/api')
app.use('/user', apis)
/**
* 404 Handler
*/
app.use((req, res, next)=>{
return res.status(404).send("Endpoint "+req.url +" not found");
})
/**
* if any error or exception occurred then write into a JS file so that app can be restarted
*/
process.on('uncaughtException', (err) => {
console.error(err.stack);
});
app.listen(3000, function(server) {
console.log("App listening at 3000");
});
When index.js file has been executed successfully and listening to a port 3000, then use this URL http://localhost:3000/user/login
for authentication, it will accept your username and password, then authenticate using passport and send a token to the client as response. The token can contain user data in encrypted form and have expiry time.
Reference link: https://github.com/arjun-707/login-logout-jwt-nodejs
You need the express-session
module.
server.js
// Require a possible config.js file with your configuration variables const Config = require('./models/config.js'); // If the config module is formed as a class const config = new Config(); const express = new('express'); const app = express(); const session = require('express-session'); const MongoStore = require('connect-mongo')(session); const uuid = require('uuid/v4'); const mongoose = require('mongoose'); // Require your custom passport local strategy file const passport = require('./models/sessions'); mongoose.connect('mongodb://localhost:27017/your_db_name', { useNewUrlParser: true }); // Set the session options app.use(session({ // Use UUIDs for session IDs genid: (req) => { return uuid() }, // If you want to store the session in MongoDB using mongoose // Require your personal mon store: new MongoStore({ mongooseConnection: mongoose.connection }), // Define the session secret in env variable or in config file secret: process.env.SESSION_SECRET || config.sessionSecretKey, resave: false, saveUninitialized: true })); // Initialize the passport module app.use(passport.initialize()); // Tell to passport to use session app.use(passport.session());
./models/session.js
const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; const bcrypt = require('bcrypt-nodejs'); // Your custom MongoDB connection module const db = require('./db'); // Configure passport.js to use the local strategy passport.use(new LocalStrategy({ usernameField: 'username' }, (username, password, done) => { db.User.find({ username: username // But it could use email as well }).then(res => { const user = JSON.parse(JSON.stringify(res[0])); if (!user) { return done(null, false, { message: 'Invalid credentials.\\n' }); } if (!bcrypt.compareSync(password, user.password)) { return done(null, false, { message: 'Invalid credentials.\\n' }); } return done(null, user); }).catch(error => done(error)); } )); // Tell passport how to serialize the user passport.serializeUser((user, done) => { done(null, user._id); }); // Tell passport how to deserialize the user passport.deserializeUser((id, done) => { db.User.find({ _id: id }).then(res => { const response = typeof res !== undefined && res.length != 0 ? JSON.parse(JSON.stringify(res[0])) : null; done(null, response) }).catch(error => done(error, false)) }); // Export passport for external usage module.exports = passport;
./models/db.js
const mongoose = require('mongoose'); const Schema = mongoose.Schema; const uuid = require('uuid/v4'); // Connect to MongoDB mongoose.connect('mongodb://localhost:27017/your_db_name', { useNewUrlParser: true }); // Define the models container let models = {}; // Prepare your user schema const userSchema = Schema({ username: { type: String, required: true }, password: { type: String, required: true } }); // Assign the user schema models.User = mongoose.model('User', userSchema); // Export for external usage module.exports = models; /* In that way you can wrap in "models" all schemas: const newSchema = Schema({ name: String }); models.Newschema = mongoose.model('Newschema', newSchema); module.exports = models; And use it externally like: const db = require('./models/db'); db.User.find({}).then(docs => {}).catch(err => {}); db.Newschema.find({}).then(docs => {}).catch(err => {}); Etc.... */
./models/config.js
class Config { constructor() { this.sessionSecretKey = "my-awesome-secretkey"; /* And other configurations */ } } module.exports = Config; /* Externally use like: const Config = require('./models/config'); const config = new Config(); let sessionSecretKey = config.sessionSecretKey; */
Then you can use the req.isAuthenticated()
after the login:
// POST the username and password to '/login' router app.post('/login', (req, res, next) => { passport.authenticate('local', (err, user, info) => { if (info) { return res.send(info.message) } if (err) { return next(err); } if (!user) { return res.sendStatus(404); // Is a shortcut // OR -> res.status(404).end(); // OR -> res.status(404).send('Not found'); as you like } req.login(user, (err) => { if (err) return next(err); // Store the user object retrieved from MongoDB in `req.session` req.session.user = user; return res.sendStatus(200); // Is a shortcut // OR -> res.status(200).end(); // OR -> res.status(200).send('OK'); as you like }) })(req, res, next); }); // The logout logic app.get('/logout', verifySession, function (req, res) { req.session.destroy(function (err) { req.logout(); res.redirect('/'); }); }); // Verify the session to protect private routers function verifySession(req, res, next) { if (req.isAuthenticated()) { next(); } else { // Forbidden res.redirect('/'); // OR -> res.sendStatus(403); // OR -> res.status(403).end(); // OR -> res.status(403).send('Forbidden'); as you like } }
Of course you have to run npm install
with all the dependencies required defined in package.json
file or manually instal with npm i express-session@latest --s
for all the dependencies required: npm i module-name@latest --s
.
Don't forget the
const server = app.listen(config.port || 3000, () => {
console.log(`Server running on ${server.address().port} port.`);
});
At the end of server.js
file. I hope that it will be useful for you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.