I have a login system, user posts data to /login route and it saves data if logged correctly.
router.post('/login', function(req, res, next) {
if(req.method == 'POST') {
const username = req.body.username;
const password = req.body.password;
sql.query('SELECT * FROM `users` WHERE `username` = "' username '"', function(err, results) {
if(err) {
req.session.message = {status: 'danger', message: 'Failed to login, check password.'}
res.redirect('/')
} else if (results.length != 0) {
const passw = results[0].password;
bcrypt.compare(password, passw, function(err, result) {
if(result) {
req.session.loggedin = true;
req.session.data = results[0];
req.session.message = {status: 'success', message: `Welcome back, ${username}.`}
req.session.save(function(err) {
res.redirect(req.headers.referer);
})
} else {
req.session.message = {status: 'danger', message: 'Failed to login, check password.'}
res.redirect('/')
}
});
} else {
req.session.message = {status: 'danger', message: 'Failed to login, check username.'}
res.redirect('/')
}
})
}
});
so it saves the data and redirects to index but everytime a user goes on the index page it shows the Welcome message, it obviously does this because the variable is still defined so my goal is to change that variable too null after they login and the welcome message shows up once.
ive tried:
delete req.session.message
but this just deletes the variable before it gets passed to the next request.
How im displaying the message:
<script type="text/javascript">
var message = JSON.parse('<%- JSON.stringify(message) %>');
$(document).ready(function(){
if(message != null) {
$('.toast').addClass('bg-' message.status);
$('.toast-body').html(message.message)
$(".toast").toast('show');
}
});
</script>
How im rendering the data:
if(req.session.loggedin) {
res.render('index', {
loggedin: true,
data: req.session.data,
message: req.session.message
});
} else {
res.render('index', {
loggedin: false,
data: null,
message: req.session.message
});
}
CodePudding user response:
After you render your page containing the message, you need to clear the message from the session:
if (req.session.loggedin) {
res.render('index', {
loggedin: true,
data: req.session.data,
message: req.session.message
});
} else {
res.render('index', {
loggedin: false,
data: null,
message: req.session.message
});
}
req.session.message = null;
req.session.save();
And, to avoid any chance of a race condition between a redirect and saving the session, you should not redirect until you've manually saved the session. The issue is that relying on the auto-save of the session by express-session will attempt to save the session AFTER you send the res.redirect()
, but sending the res.redirect()
tells the browser to immediately request another page so you set up a race between the auto-save of the session and the new incoming request from res.redirect()
. You don't want that race. You want to make sure the session has been saved before you issue the redirect. So, I put the res.redirect()
inside a req.session.save()
callback to avoid any possible race condition:
router.post('/login', function(req, res, next) {
if(req.method == 'POST') {
const username = req.body.username;
const password = req.body.password;
sql.query('SELECT * FROM `users` WHERE `username` = "' username '"', function(err, results) {
if(err) {
req.session.message = {status: 'danger', message: 'Failed to login, check password.'}
res.redirect('/')
} else if (results.length != 0) {
const passw = results[0].password;
bcrypt.compare(password, passw, function(err, result) {
if(result) {
req.session.loggedin = true;
req.session.data = results[0];
req.session.message = {status: 'success', message: `Welcome back, ${username}.`}
req.session.save(function(err) {
res.redirect(req.headers.referer);
})
} else {
req.session.message = {status: 'danger', message: 'Failed to login, check password.'}
req.session.save(() => {
res.redirect('/')
});
}
});
} else {
req.session.message = {status: 'danger', message: 'Failed to login, check username.'}
req.session.save(() => {
res.redirect('/')
});
}
})
}
});