I set up a navbar.ejs as a partial so that i don't need to rewrite it again. Every routes require navbar.ejs. Im using passport for Auth
<% if (!user) { %>
<li>Signup</li>
<li>Login</li>
</ul>
<% } else{ %>
<li>Dashboard</li>
<li><a><%= user.profile.name %></a></li>
<% } %>
Example routes
app.get('/', function(req, res) {
res.render('home');
}
app.get('/dashboard', isLoggedIn, function(req, res) {
res.render('dashboard', { user: req.user });
}
app.get('/about', function(req, res) {
res.render('about');
}
For routes that have user's object as the response are working fine when rendered but others will keep showing
user is not defined
I know that the obvious solution is to pass in a user's object in every single route, but that is really insane.
Imagine if I have to do this
app.get('/1', function(req, res) {
res.render('/1', {user: req.user});
}
app.get('/2', function(req, res) {
res.render('/2', {user: req.user});
}
app.get('/3', function(req, res) {
res.render('/3', {user: req.user});
}
app.get('/4', function(req, res) {
res.render('/4', {user: req.user});
}
app.get('/5', function(req, res) {
res.render('/5', {user: req.user});
}
If routes that require authentication, I don't really mind to pass the user's object, but simple routes like home, about or contact I don't feel like the need to pass in.
If you don't want to keep passing the user's object in every single route then you have to set up a middleware
somewhere after your passport configuration add the following codes
app.use(function(req, res, next){
res.locals.user = req.user;
});
then you no longer needed to pass the user's object in every single route
app.get('/1', function(req, res) {
res.render('/1');
}
app.get('/2', function(req, res) {
res.render('/2');
}
Related
I want to put information about user (information from discord, like username and discriminator) in website. When authorized, all data in formal JSON. Here's code.
"/callback",
passport.authenticate("discord", { failureRedirect: "/" }),
function(req, res) {
res.redirect("/dashboard");
} // auth success
);
app.get("/logout", function(req, res) {
req.logout();
res.redirect("/");
});
app.get("/dashboard", checkAuth, function(req, res) {
//console.log(req.user)
res.json(req.user);
});```
My view relies on some data to render, like this:
router.get("/", (req, res) => {
res.render(
'index', {
data: layout_data,
user: req.user
}
);
});
router.post('/login', passport.authenticate('local'), function(req, res) {
res.redirect('/');
});
It works. But when I added the csurf middleware like
router.post('/login', parseForm, csrfProtection, passport.authenticate('local'), function(req, res) {
res.redirect('/');
});
The layout engine tells me that data is undefined. I suspect that the csurf middleware erases the data.
I tried to fix it like this:
router.get("/", (req, res) => {
req.mydata = {};
req.mydata.layout_data = layout_data;
res.render(
'index', {
data: req.mydata.layout_data,
user: req.user
}
);
});
router.post('/login', parseForm, csrfProtection, passport.authenticate('local'), function(req, res) {
if (!req.mydata) {
req.mydata = {};
}
req.mydata.layout_data = layout_data;
res.redirect('/');
});
It still does not work. The data is still undefined.
What is the best practice to resolve this problem?
My guess is: your layout_data is undefined.
I give 401 Uanthourised acces header with
module.exports = function() {
return function(req, res, next) {
if (!req.isAuthenticated()) {
res.status(401);
console.log('Unauthorized');
res.render('login.html', { csrfToken: req.csrfToken() });
return;
}
next();
};
};
Now login.html is a view handled by completly different controller:
var passport = require('passport');
var config = require(__dirname + '/../lib/config');
module.exports = function (router) {
router.get('/', function (req, res) {
// Error flash messages
var errorFlash = req.flash('error');
if (errorFlash && errorFlash.length) {
res.locals.error = errorFlash;
}
res.render('login.html', { csrfToken: req.csrfToken() });
});
router.post('/',
passport.authenticate('local', {
failureRedirect: '/login/',
failureFlash: true
}),
function(req, res) {
res.cookie(config.cookie.name, req.user.email, { signed: true, maxAge: 1234 });
res.redirect('/');
}
);
};
My concern is how I can be sure what part of login controller fires up? render('index.html') somehow hooks up to router.post() in index controller and login form is handler as usual. How that can be?
If you ever have any doubt which function is being called then a good approach is to (temporarily) add a console.log() within that function. I will often do something like:
console.log('filename.js - functionname() called with args: [%s] [%s]', arg1, arg2);
And then watch the log for information about what fired off and what variables you're trying to watch.
It could be that you need to redirect rather than render in your 401-related code.
res.redirect('/login');
(Edited)
The controller will always go to "index" if you did not provide any method.
The reason that it is a "POST" is probably that you are trying to send a form to the index page.
If you just request the index page. for example "(url)/login/index" or just "(url)/login" then it would be a "GET" request, but what are you trying to tell, I don't understand your question completely
I've been reading passport.js info and samples for two days, but I'm not sure after that I did all the process of authenticating.
How do I know if I'm logged in, for example, I'll have a navigation bar with a login or logout button, is there some variable like code below?
if (login)
<button>logout</button>
else
<button>login</button>
If user is logged in, passport.js will create user object in req for every request in express.js, which you can check for existence in any middleware:
if (req.user) {
// logged in
} else {
// not logged in
}
You can create simple express.js middleware for that, that will check if user is logged in, and if not - will redirect to /login page:
function loggedIn(req, res, next) {
if (req.user) {
next();
} else {
res.redirect('/login');
}
}
And use it:
app.get('/orders', loggedIn, function(req, res, next) {
// req.user - will exist
// load user orders and render them
});
If you would like to use it in your templates as your code sample seems to indicate you can create some middleware such as this:
app.use(function (req, res, next) {
res.locals.login = req.isAuthenticated();
next();
});
Place that code somewhere after you have setup passport.
And then use it in your template (swig example)
{% if login %}
<button>logout</button>
{% else %}
<button>login</button>
{% endif %}
It is not explicitly documented but there is a isAuthenticated() method which is inserted into req by passport.
Can be used as follows,
req.isAuthenticated() // returns true if auth, false if not
// auth.js
module.exports = {
ensureAuthenticated: (req, res, next) => {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login') // if not auth
},
forwardAuthenticated: (req, res, next) => {
if (!req.isAuthenticated()) {
return next()
}
res.redirect('/dashboard'); // if auth
}
}
// app.js
app.get('/dashboard', ensureAuthenticated, (req, res) => res.render('dashboard'))
app.get('/login', forwardAuthenticated, (req, res) => res.render('login'))
app.get('/register', forwardAuthenticated, (req, res) => res.render('register'))
I was searching such solution and came across this page. Question is how to check login status on client side.
After logging I hide the Login button and show the logout button. On page refresh I again see the login button instead of logout button. The only solution is to save an item in sessionStorage if you are using session (and localStorage if you are using JWT). Delete this item when you logout.
Then in every page load check this sessionStorage item and do accordingly.
if (sessionStorage.getItem('status')) {
$("#btnlogout").show();
$("#btnlogin").hide();
// or what ever you want to do
} else {
$("#btnlogout").hide();
$("#btnlogin").show();
}
function Login() {
var data = {
username: $("#myModal #usr").val(),
password: $("#myModal #pw").val()
};
$.ajax({
type: 'POST',
url: '/login',
contentType: 'application/JSON; charset=utf-8',
data: JSON.stringify(data),
success: funcSuccess,
error: funcFail
});
function funcSuccess(res) {
sessionStorage.setItem('status', 'loggedIn');
$("#btnlogout").show();
$("#btnlogin").hide();
}
function funcFail() { $("#pp").text('Login Failed'); };
};
function Logout() {
$.ajax({
type: 'GET',
url: '/logout',
contentType: 'application/JSON; charset=utf-8',
success: funcSuccess,
error: funcFail,
});
function funcSuccess(res) {
$("#btnlogout").hide();
$("#btnlogin").show();
sessionStorage.removeItem("status");
};
function funcFail() { alert('Login method Failed'); };
};
use below code inside app.get() or router.get()
router.get('/edit/:id', (req, res)=>{
if(req.isAuthenticated()){
if(req.isAuthenticated()){
//
}
else{
res.redirect('/users/login');//your particular login routes
}
});
Good question, I had some issues while trying to implement something like this, when there is a un-authenticated request the handlebars skips the if block if the res.locals variable returns a falsy value. To solve this issue you need to setup a middleware in your app.js file to make the req.user available globally in your app Like so..
app.use(function (req, res, next) {
res.locals.login = req.user;
next();
});
In your header file you can do this check for authenticated user and display according content like so..
{{#if login }}
<li>User Account</li>
<li role="separator" class="divider"></li>
<li>Logout</li>
{{/if}}
{{#unless login}}
<li>Sign up</li>
<li>Sign in</li>
{{/unless}}
We have an app with the following routes
/dothis/
...//dothis routes
/dothat
...//dothat routes
/doother
...//doother routes
and a login route:
/login
and
/ //which currently actually isn't even used, would redirect to /login
Is it possible to close the routes so that actually only / and /login are accessible without authentication? Or do we need to apply a prefix to all other routes. Thanks
app.get('*', function(req, res, next) {
// console.log(everyauth);
if (!req.session.auth) {
res.redirect('/login');
} else {
next();
}
});
app.get('/login', function(req, res){
res.render('login', {
});
});
seems to work
app.all('*', Authentication, function(req, res) {
});
function Authentication(req, res, next) {
if (req is not user) {
if (req.url === '/' || req.url === '/login')
next()
}
else
next();
}
I have middleware which does exactly this: https://github.com/jaredhanson/connect-ensure-login
app.get('/dothat',
ensureLoggedIn('/login'), // redirect to /login if not logged in
function(req, res) {
// render do that;
});
It's usable stand-alone, but also integrates seamlessly with Passport, so that after login, the user will be redirected back to the URL they originally requested.