i'm trying to put passport logic in controllers file but the problem is when i put the logic inside the controllers it's tell me "Cannot read property 'body' of undefined" but when i move the code to the index routes everything goes right
index.js/controller the problem is in " postLogin "
const User = require('../models/user');
const passport = require('passport');
module.exports = {
async postRegister(req, res, next) {
const newUser = new User({
username: req.body.username,
email: req.body.email,
image: req.body.image
})
await User.register( newUser , req.body.password);
res.redirect('/');
},
postLogin(req, res, next) {
passport.authenticate('local', { successRedirect: '/' ,failureRedirect: '/login' })();
}
}
index.js/routes
const express = require('express');
const router = express.Router();
const { postRegister, postLogin } = require('../controllers/index');
const { errorHandler } = require('../middleware/index');
/* GET home page. */
router.get('/', (req, res, next) => {
res.render('index', { title: 'Surf Shop - Home' });
});
/* User routs */
//Get register
router.get('/register', (req, res, next) => {res.send('/register')});
//POST register
router.post('/register', errorHandler(postRegister));
//Get login
router.get('/login', (req, res, next) => { res.send('GET /Login') });
//POST login
router.post('/login', postLogin);
module.exports = router;
image form postman
Are the brackets intentional at the end of:
passport.authenticate('local', { successRedirect: '/' ,failureRedirect: '/login' })() <----
Issue with parameters not being passed?
router.post('/login', postLogin);
Becomes:
router.post('/login', () => {
postLogin(req, res, next)
});
Correct resolve:
Very helpful but the parameters not being passed here
passport.authenticate('local', { successRedirect: '/' ,failureRedirect: '/login' })(here)
So becomes
`passport.authenticate('local', { successRedirect: '/' ,failureRedirect: '/login' })(req, res, next)`
Related
When I'm trying to get to http://localhost:7000/logout, the URL redirects me to the main page. And it doesn't sign me out from my Google account. I want to show message "You are logged out" and then I want this code to ask user to log in again.
const express = require('express');
const session = require('express-session');
const passport = require('passport');
require('./auth');
const app = express();
function isLoggedIn(req, res, next) {
req.user ? next() : res.sendStatus(401);
}
app.use(session({ secret: 'cats', resave: false, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.get('/', (req, res) => {
res.send('Authenticate with Google');
});
app.get('/auth/google',
passport.authenticate('google', { scope: [ 'email', 'profile' ] }
));
app.get('/google/callback',
passport.authenticate('google', {
successRedirect: '/protected',
failureRedirect: '/auth/failure',
})
);
app.get('/auth/failure', (req, res) => {
res.send('something went wrong..');
});
app.get('/protected', isLoggedIn, (req, res) => {
res.send(`Hello ${req.user.displayName}`);
});
app.get('/logout', function(req, res, next) {
req.logout(function(err) {
if (err) { return next(err); }
res.redirect("/");
});
});
app.listen(7000, () => console.log('listening on port: 7000'))
I'm having a small problem here. I want to display 404 not found if I input a wrong route.
The code below only shows 404 not found if I go to http://localhost:3000/
but when I enter http://localhost:3000/wrongroute it displays Cannot GET /wrongroute instead of
404 not found.
const bodyParser = require("body-parser");
const mysql = require('mysql');
const router = express.Router();
const db = mysql.createConnection({
host: 'xxx.xx.xx.xx',
user: 'root',
password: '12345',
database: 'test'
});
db.connect((err) =>{
if(err){
throw err;
}
console.log('Mysql Connected');
// res.send("Mysql Connected");
});
router.post('/login', function (req, res) {
res.send("This is from login route");
res.end();
})
router.post('/signup', function (req, res) {
res.send("This is from signup route");
res.end();
})
router.get('/', function(req, res){
res.send("404 not found");
});
module.exports = router;
Add this route at the END.
router.get("*", (_, res) => res.status(404).send("404 not found"))
Here's your solution. Remember to place the fallback route at the end of your endpoint list.
router.post('/your-route', function (req, res) {
...
});
router.post('/another-route', function (req, res) {
...
});
router.get('*', function(req, res) {
// This is a fallback, in case of no matching
res.status(404);
res.send('Not found.');
});
CURRENT SCENARIO
Once I log in via social auth it shows the username and provider detail on the page. but if I refresh again it shows the error. I am sending the user object via render but still, it doesn't fetch the details. I don't understand why.
{"error":{"message":"Failed to fetch user profile"}}
Below is my express session snippet in my app.js file
app.use(expressSession({
name: 'Session',
maxAge: 24 * 60 * 60 * 1000,
secret: [keys.session.cookieKey],
resave: true,
saveUninitialized: true
}))
app.use(passport.initialize())
app.use(passport.session())
Below is my oauth.js file
const express = require('express');
const router = express.Router();
const passport = require('passport')
router.get('/login',(req, res, next) => {
//create a func where we check if the user logged in then show the profile page , if not logged in then show login page
res.render('login')
});
router.get('/logout', (req, res, next) => {
req.session = null
req.logout()
res.redirect('/')
});
router.get('/google', passport.authenticate('google', {
scope: ['profile']
}));
router.get('/facebook', passport.authenticate('facebook', {
scope: ['profile']
}));
router.get('/twitter', passport.authenticate('twitter', {
scope: ['profile']
}));
router.get('/github', passport.authenticate('github', {
scope: ['profile']
}));
router.get('/google/redirect', passport.authenticate('google', {
failureRedirect: '/login'
}), (req, res, next) => {
res.render('profile', {
user: req.user
})
});
router.get('/facebook/redirect', passport.authenticate('facebook', {
failureRedirect: '/login'
}), (req, res, next) => {
res.render('profile', {
user: req.user
})
});
router.get('/twitter/redirect', passport.authenticate('twitter', {
failureRedirect: '/login'
}), (req, res, next) => {
res.render('profile', {
user: req.user
})
});
router.get('/github/redirect', passport.authenticate('github', {
failureRedirect: '/login'
}), (req, res, next) => {
console.log('user details: '+req.user)
res.render('profile', {
user: req.user
})
});
module.exports = router;
I'm trying to add user-login module to an existing app in node. It is using separate route files for each module and one main route file to use all the child routes which is ultimately used in server.js
When I try to pass passport instance to the user route, it gives me error as passport is not defined. Here is my app code and structure:
app
views
user
index.ejs
login.ejs
signup.ejs
profile.ejs
routes
docs
index.js
user
index.js
index.js
config
passport.js
server.js
server.js
const express = require('express')
const app = express()
const path = require('path')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const passport = require('passport')
const flash = require('connect-flash')
const session = require('express-session')
const routes = require('./routes/')
const port = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
require('./config/passport')(passport);
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(bodyParser.json());
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(session({ secret: '********' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use('/', routes)(app,passport);
const server = app.listen(port, function(){
console.log('Server listening on port '+port);
});
config/passport.js
var LocalStrategy = require('passport-local').Strategy;
const sql = require('mssql')
const bcrypt = require('bcrypt-nodejs')
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function (username, done) {
done(null,username);
});
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
process.nextTick(function() {
var strSQL = "SELECT count(id) as uCount FROM <tbl> WHERE username = '"+email+"'";
var cb1 = function(err,recordset){
if(recordset[0].uCount>0){
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else{
var strSQL1 = "INSERT INTO <tbl>(username, password) VALUES('"+email+"','"+generateHash(password)+"')";
var cb2 = function(err,recordset){
return done(null, recordset,req.flash('signupMessage', 'Email registered successfully.'));
};
executeQuery(strSQL1,'INSERTION','<tbl>',cb2);
}
};
executeSelection(strSQL,'SELECTION','<tbl>',cb1);
});
}));
passport.use('local-login', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
var strSQL = "SELECT a.count, id, username, password FROM <tbl> c , (SELECT COUNT(dbid) count FROM <tbl> b WHERE b.username = '"+email+"' ) a WHERE c.username = '"+email+"'";
var cb1 = function(err,recordset){
if(recordset[0].uCount <= 0){
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (!validPassword(password,recordset[0].password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
return done(null, recordset[0]);
};
executeSelection(strSQL,'SELECTION','<tbl>',cb1);
}));
};
executeSelection = function(strSQL, operationType, tableName, cb){
var request = new sql.Request(connection);
request.query(strSQL,function(err,recordset) {
if(err){
logger.error('ERROR in '+operationType+' ON '+tableName+': '+err);
}
logger.info(operationType+' ON '+tableName+' successful!');
cb(err,recordset);
});
};
executeQuery = function(strSQL, operationType, tableName, cb,validateClient) {
var request = new sql.Request(connection);
request.query(strSQL,function(err, recordset) {
if(err){
logger.error('ERROR in '+operationType+' ON '+tableName+': '+err);
}
logger.info(operationType+' ON '+tableName+' successful!');
if(cb){
cb(validateClient);
}
});
};
generatePasswordHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
validatePassword = function(curPass, dbPass) {
return bcrypt.compareSync(curPass, dbPass);
};
routes/index.js
const mainroute = require('express').Router()
/* ---- other existing routes included ---- */
const r_docs = require('./docs')
const r_user = require('./user') /*my custom route*/
/* ---- all other routes ---- */
mainroute.use('/docs', r_docs);
mainroute.use('/user', r_user)(app, passport); /*my custom route*/
mainroute.get('/', function(req, res){
res.render('home');
});
module.exports = function(app, passport){
mainroute;
}
routes/user/index.js
const express = require('express')
const router = express.Router()
router.get('/', function(req, res) {
res.render('user/index.ejs');
});
router.get('/login', function(req, res) {
res.render('user/login.ejs', { message: req.flash('loginMessage') });
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
router.get('/signup', function(req, res) {
res.render('user/signup.ejs', { message: req.flash('signupMessage') });
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile',
failureRedirect : '/signup',
failureFlash : true
}));
router.get('/profile', isLoggedIn, function(req, res) {
res.render('user/profile.ejs', {
user : req.user
});
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
module.exports = function(app, passport) {
router;
}
Please suggest what am I doing wrong here. Thanks
You should wrap your main and user routes to run their logic when you call them and at end return prepared route:
routes/index.js
module.exports = function(app, passport) {
const mainroute = require('express').Router()
/* ---- other existing routes included ---- */
const r_docs = require('./docs');
const r_user = require('./user'); /*my custom route*/
/* ---- all other routes ---- */
mainroute.use('/docs', r_docs);
mainroute.use('/user', r_user)(app, passport); /*my custom route*/
mainroute.get('/', function(req, res) {
res.render('home');
});
return mainroute;
};
routes/user/index.js
module.exports = function(app, passport) {
const express = require('express');
const router = express.Router();
router.get('/', function(req, res) {
res.render('user/index.ejs');
});
router.get('/login', function(req, res) {
res.render('user/login.ejs', {
message: req.flash('loginMessage')
});
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
}));
router.get('/signup', function(req, res) {
res.render('user/signup.ejs', {
message: req.flash('signupMessage')
});
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
router.get('/profile', isLoggedIn, function(req, res) {
res.render('user/profile.ejs', {
user: req.user
});
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
return router;
};
You need to require it at the top of your user/index.js. Simply:
var passport = require('passport');
Then to make sure the user is authenticated:
router.get('/some/path', isLoggedIn, function(req, res) {
var user = req.user;
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
Things are sort of working but, for some reason, I can't get the user_id into the URL, all I get is a literal ":user_id" like so:
here is the code in the my users.js route file
var main = require('../main');
exports.getAllUsers = function(req, res) {
var db = main.db();
db.collection('users').find().toArray(function(err, items) {
res.json(items);
});
};
exports.routeUserToTheirHome = function(req, res, next) {
res.json(req.user);
};
and here is the code in my main.js file:
app.param('user_id', function(req, res, next, user_id) {
// typically we might sanity check that user_id is of the right format
User.find(user_id, function(err, user) {
if (err) {
return next(err);
}
if (!user) {
return new Error("no user matched");
}
req.user = user;
next();
});
});
app.use('/users/:user_id/home', users.routeUserToTheirHome);
exports.routeUserToTheirHome = function(req, res, next) {
req.user.user_id = req.params.user_id;
res.json(req.user);
};
I figured out what the problem was, it was that I had this:
app.post('/login', passport.authenticate('local', {
successRedirect : 'users/:user_id/home',
failureRedirect : '/login',
failureFlash : true
}), function(req, res, next) {
next();
});
when in fact, I needed this:
app.post('/login', passport.authenticate('local', {
successRedirect : 'users/' + '5464370621a2569c18880876' +'/home',
failureRedirect : '/login',
failureFlash : true
}), function(req, res, next) {
next();
});
clearly I don't know what I am doing. The question now is, where do I get the user_id from, instead of hardcoding it?
here is the solution:
app.post('/login', passport.authenticate('local', {
failureRedirect : '/login',
failureFlash : true
}), function(req, res, next) {
res.redirect('users/' + req.user._id +'/home');
next();
});