I am trying to redirect back to the page when I am redirected to log in. I am using Passport and connect-ensure-login, and the login works, however, it gets annoying having to re-click the link (if you are not logged in, it redirects you to the home page, but the link has a query string). Is there a way to add a redirect URL upon successful log-in?
The redirect URL needs to be dynamic, because it is query strings, and is not dependent upon the user’s id or anything like that.
Here is a snippet of my server-side code (please tell me if you need any other snippets because my app.js is 224 lines long and I don’t want to post that).
app.js
:
let express = require( 'express' ); let app = express(); const expressSession = require('express-session')({ secret: `secret`, resave: false, saveUninitialized: false }); app.use(expressSession); const passport = require('passport'); app.use(passport.initialize()); app.use(passport.session()); let path = require( 'path' ); const passportLocalMongoose = require('passport-local-mongoose'); const connectEnsureLogin = require('connect-ensure-login'); var mongoose = require("mongoose"); var bodyParser = require("body-parser"); const Mixed = mongoose.Schema.Types.Mixed; mongoose.Promise = global.Promise; mongoose.connect('mongodb://localhost/db', { useNewUrlParser: true, useUnifiedTopology: false }); const Schema = mongoose.Schema; const UserDetail = new Schema({ username: String, email: Mixed, password: String, verified: Boolean }); UserDetail.plugin(passportLocalMongoose); const UserDetails = mongoose.model('userInfo', UserDetail, 'userInfo'); passport.use(UserDetails.createStrategy()); passport.serializeUser(UserDetails.serializeUser()); passport.deserializeUser(UserDetails.deserializeUser()); app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })); app.use( '/login', express.static( path.join( __dirname, 'login' ) ) ); app.get( '/', connectEnsureLogin.ensureLoggedIn(), ( req, res ) => { res.sendFile( __dirname + '/index.html' ); }); app.post('/login', (req, res, next) => { passport.authenticate('local', (err, user, info) => { if (err) { return next(err); } if (!user) { return res.redirect('/login?info=' + info); } req.logIn(user, function(err) { if (err) { return next(err); } return res.redirect('/'); }); })(req, res, next); }); app.get('/login', (req, res) => { res.sendFile('login/login.html', { root: __dirname }) }); app.get('/register', (req, res) => { res.sendFile('login/register.html', { root: __dirname }) }); app.get('/user', connectEnsureLogin.ensureLoggedIn(), (req, res) => { res.send({user: req.user}) }) app.post('/register', (req, res) =>{ UserDetails.register({ username: req.body.username, active: false, email: req.body.email }, req.body.password) res.redirect('/login') })
Is there a way to:
- Save query string in the session when using
connectEnsureLogin.ensureLoggedIn()
? - Or save the query string in another way and read that when you go to redirect?
I’m new to Node.js so I followed an example to get the Login to work (sorry, I do not have the example now, I don’t know where I found it and I didn’t save a copy of it).
Also, this question does not duplicate this SO question because I cannot think of how to implement the answer with my current middleware, connectEnsureLogin.ensureLoggedIn(). If not, please tell me how I can implement @Chovy’s answer to use my current situation.
Thanks so much!!!!
Edit:
I think it has something to do with redirectTo
in connectEnsureLogin, however, I cannot get it to read the query string. I tried to set redirectTo
to req.url
but my servers errors with:
returnTo: req.query ^ ReferenceError: req is not defined
Is there a way to do this? Thanks
Advertisement
Answer
Sadly, connectEnsureLogin
does not provide the customizations needed in your case, however, a simple middleware function does exactly what you want.
At the top, define a middleware function and set a session cookie called RedirectTo:
function auth (req, res, next) { if (req.isAuthenticated()) { // user is authenticated, so we do not need to redirect them. return next(); } else { // user is not authenticated, so add a session cookie telling our server where to redirect to. req.session.redirectTo = req.url; // redirect to login with cookie set res.redirect('/login'); } }
You can use the middleware like this:
app.get( '/', auth, ( req, res ) => { // ^^^^ notice that we use our middleware instead res.sendFile( __dirname + '/index.html' ); })
Then, you can read that session cookie in your post request handler like this:
app.post('/login', (req, res, next) => { // authentication like normal passport.authenticate('local',(err, user, info) => { if (err) { return next(err); } if (!user) { return res.redirect('/login?info=' + info); } req.logIn(user, function(err) { if (err) { return next(err); } // this is the special part // redirect the user to the session cookie if it exists var redirectTo = req.session.redirectTo || '/'; // delete the session cookie so it is not present on the next request delete req.session.redirectTo; // redirecting the user to where they want to go res.redirect(redirectTo || '/'); }); })(req, res, next); });