How can you define multiple isAuthenticated functions in Passport.js? - node.js

I am building an app using Express/Node.js with Passport.js(passport-local) & Mongoose.
There are two kind of users:
regular users (they login using /user-login page and passport strategy 'local-user-login'; regular users are stored in "Users" MongoDB collection)
admins (they login using /admin-login page and passport strategy 'local-admin-login'; admins are stored in "Admins" MongoDB collection)
I also have 2 pages: /user_home (needs to be accessible to logged regular users only) and /admin_home (for logged admins only)
Route for /user_home:
app.get('/user_home', isLoggedIn, function(req, res) {
// render the page
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/login');
}
If I log in as an admin and try to access /user_home, it doesn't allow me, which is fine. My question is: how can I define another "isLoggedIn" function that checks if I am logged in as an admin rather than a regular user? Ideally I would like to have a function "isLoggedInAsUser" and another one "isLoggedInAsAdmin".
So far I tried defining the /admin_home route the same way:
app.get('/admin_home', isLoggedIn, function(req, res) {
// render the page
});
But it's obvious why it doesn't work. The code doesn't know that I want it to check if it's an admin rather than a regular user.

Passport stores authenticated user in req.user. So you can write middleware functions like this:
function allowAdmins(req, res, next) {
if (req.user.role === 'Admin') return next();
res.redirect('/user-login');
}
function allowRegular(req, res, next) {
if (req.user.role === 'Regular') return next();
res.redirect('/admin-login');
}
And then in routes:
var userRouter = express.Router();
userRouter.use(isLoggedIn);
// Only authenticated users are allowed
userRouter.get('/home', isRegular, function (req, res) {});
userRouter.get('/admin', isAdmin, function (req, res) {});
app.use('/user', userRouter);

in session object store role information
in the route configuration level, write middleware like
var adminRoutes = express.routes();
adminRoutes.route('/admin/*', function (req, res,next)
{
if(req.session.role==='Admin')
return next();
else
{
res.send("Authorization Error")
}
}
app.use(adminRoutes);
same for user routes

Related

Conditional routing in controller not working Node Express

I've built some conditional logic to control access to a subdomain (producer.localhost:3000)
Only users with role 'admin' should be able to access the site, everyone else (with role of 'user') should be redirected to their profile page.
This is the code inside producerController.js :
index = (req, res, next) => {
if ((req.oidc.user['https://localhost:3000.com/roles']).includes("user")){
res.redirect('http://localhost:3000/user/profile')
}
else {
res.render('producer/index')
};
};
The problem is that it redirects for ALL user roles (rather than just those with ‘user’ as a role)
Doesn't seem like an express issue to me, try something like this
const express = require('express');
const app = require('express');
//Only allows users to continue to route if admin is one of their roles
const adminRoute = (req, res, next) =>{
if(req.oidc.user['https://localhost:3000.com/roles'].includes('admin'))
next();
else
res.redirect('http://localhost:300/user/profile');
}
//Example use case
//Everything affected by this app.use() (in this case anything underneath it) will only be accessible to users with the admin role
app.use('*', adminRoute)
app.get('/protectedRoute', (req, res) =>{
res.send('Protected route')
})
//Or you can use it directly inside the route
app.get('/protectedRoute', adminRoute, (req, res) =>{
res.send('Protected route')
})
app.listen('80', () =>{
console.log('Listening on port 80')
})
This should work 100% of the time, the only logical conclusion is that your if statement isn't returning the proper value.
In which case you can try using
if(array.indexOf('admin') !== -1)
The code shouldn't conflict just put them underneath eachother
//Executes this first
app.use((req, res, next) =>{
doThing();
next();
})
//Then executes the next route/use
app.use((req, res, next) =>{
doOtherThing();
if(something == false) return res.redirect('https://test.com');
next();
})
//Lastly if next was called in every use statement before this access route
app.get('/someRoute', (req, res) =>{
res.send('Accessed some route');
}
Not sure if I understand your issue

How do Allow only Admins to have access to the Admin page in Nodejs `AdminBro`

How do Allow only Admins to have access to the Admin page in AdminBro? Nodejs
All that I want is for only Admins to have access to the adminBro page, is there any specific method to get this done?
I did this in my app.js file but it's not working
app.get("/admin", function (req, res, next) {
res.locals.login = req.user;
if (res.locals.login.roles == "admin") {
app.use("/admin", adminRouter);
} else {
res.redirect("/");
}
});
You cannot use new app.use inside app.get, as (req, res, next) are already consumed. You have two of choice:
Your route in if condition body
if (res.locals.login.roles === 'admin') {
// your admin route logic
res.send('admin page')
} else {
res.redirect('/')
}
I'm used to use small middleware function like this one:
const isAdmin = (req, res, next) => {
if (req.user.roles === 'admin') {
return next();
}
res.redirect('/');
};
Then you use it in whichever route this way:
app.get('/admin', isAdmin, adminRouter)

authentication for specific routes in passport

authentication for specific routes in passport
Is there a way by which I can unauthenticate specific routes say if I want to unauthenticate /seller page..
Please help me out
You could potentially log users out when they navigate to that page using req.logout.
Example:
app.get('/seller', (req, res) => {
req.logout();
}, (req, res) => {
// seller page logic
});
If you want the users to stay logged in for other pages then I would recommend instead creating an authorization middleware so only specific users would see the seller page.
Brief example:
const authorize = (req, res, next) => {
const { user } = req;
if (user && user.loggedIn && user.admin) {
// Allow access
return next();
}
};

Passport.js: how to protect ALL routes?

I followed the documentation for passport.js with passport-local: http://www.passportjs.org/docs/authorize/
When I send my users to /login they are authenticated, but nowhere in that document can I find how to authorise my users.
I've tried this, but that gives me a bad request:
router.get('/somepage', passport.authenticate('local'), function(req, res, next) {
});
I'm looking for way to protect all my pages at once. I'm working with Express 4.16 and use different route files to split up my routes.
Sam
you can use middleware with a small trick to switch between strategies
example:
const allowUrl = ['public', 'nonprivate','home'];
const authenticationMiddleware = (whiteList =[]) => (req, res, next) => {
if(whiteList.find(req.baseUrl)) {
next();
}
if (req.isAuthenticated()) {
return next()
}
res.redirect('/');
}
app = express();
app.use(passort.initialize());
app.use(authenticationMiddleware(allowUrl));
app.use(apiRouter);
app.listen(3000, ()=> console.log('hello internet');
you can add your middleware code like below
router.get('/', isAuthenticated, function(req, res) {
//your next function
});
function isAuthenticated(req, res, next) {
// do any checks you want to in here
// CHECK THE USER STORED IN SESSION FOR A CUSTOM VARIABLE
// you can do this however you want with whatever variables you set up
if (req.user.authenticated)
return next();
// IF A USER ISN'T LOGGED IN, THEN REDIRECT THEM SOMEWHERE
res.redirect('/');
}
As I wanted ALL routes (except for login routes off course) to pass authorization, I solved it as follows:
var ensureAuthenticated = function(req, res, next) {
if (req.isAuthenticated()) return next();
else res.redirect('/login')
}
// usersRouter contains all open routes like '/login':
app.use('/', usersRouter);
// From here on, all routes need authorization:
app.use(ensureAuthenticated);
app.use('/', indexRouter);
app.use('/api/foo', fooRouter);
app.use('/api/bar', barRouter);
I'm not sure what do you mean by "but nowhere in that document can I find how to authorise my users". Passportjs won't authorize any user. It is an authentication middleware. Authorization is different from authentication.
I think you are looking for application level middleware. You have to use app.use to make authentication work for each request to the server.
You can read more about it here. https://expressjs.com/en/guide/using-middleware.html#middleware.application

How to pass user data into all all views?

I can't work out how best to pass user details (email, name, etc.) to 'logged in' views (I'm using jade).
I'm using passport and have access to session.passport.user in my views but only the user's _id is saved on here, and i've been told it would be bad security practice to persist it locally in the session cookie.
I don't want to have to pass a user object to res.render on each controller that I need the user.
this is how i have sessions setting up locally
app.use(function (req, res, next) {
res.locals.session = req.session;
next(null, req, res);
});
and this is my middleware to check if a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated()) {
return next();
}
// if they aren't redirect them to the home page
res.redirect('/');
}
I have looked at dynamic helpers but I'm using express v3.0.0rc4.
You can use res.locals for this purpose. Anything you put in that object will be available in the view context (unless, of course, it's overridden by a later context). So, for example, you could modify your isLoggedIn middleware thusly:
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated()) {
// obviouisly, don't use static strings...
// get these values from your authentication
// mmechanism
res.locals.user = 'username';
res.locals.userEmail = 'user#domain.com';
return next();
}
// if they aren't redirect them to the home page
res.redirect('/');
}

Resources