NodeJS + Route with custom ACL - node.js

i am newbie in nodeJS. i have an issue with route.
SiteRoutes.js
module.exports = (app, express) => {
const router = express.Router();
const Globals = require("../../configs/Globals");
const SiteController = require("../controllers/SiteController") ;
router.post('/changeStateSite', Globals.isAdminAuthorised, (req, res, next) => {
const siteObj = new SiteController().boot(req, res);
return siteObj.statusSite();
});
app.use(config.baseApiUrl, router);
}
Globle.js
static async isAdminAuthorised(req, res, next) {
// checking the role. currently only admin role consider so we have set a static role as a admin.
}
right now Globals.isAdminAuthorised is used for the ACL, but i need to pass the custom user role in that function like Globals.isAdminAuthorised(['admin','customer']) so how can i do that?
As when i pass the same its throw the error as below:
please help me on the same.

you can make that middleware a function that returns the handler function with (req, res, next) signature, so basically it will take that array as a parameter.
// e.g roles is that array that you can pass to do authorization logic based on that
static async isAdminAuthorised(roles) {
return function (req, res, next) {
// check if the roles are included in that array for example or whatever...
}
}
then you can just execute that function inside your router there like how you wrote up there
router.post('/changeStateSite', Globals.isAdminAuthorised(['admin', 'customer']), (req, res, next) => {...}

Related

Express - using application-level middleware conditionally on route-level

I'm trying to understand how to use an application-level middleware (or at least usually used like this) like cookie-parser on route-level and conditionally.
I tried something like:
const myMiddleware = (req, res, next) => {
if (myCondition) {
return cookieParser();
} else {
next();
}
}
app.use('/admin', myMiddleware, (req, res) => {
res.sendStatus(401)
})
But it's not working, the request will be just stuck.
Is this possible?
Traditional cookie-parser implementation:
app.use(cookieParser())
cookieParser() returns a middleware function, i.e. a function that takes in req, res, next as arguments. You just have to pass it the arguments:
const cookieParserMiddleware = cookieParser();
const myMiddleware = (req, res, next) => {
if (myCondition) {
return cookieParserMiddleware(req, res, next);
}
next();
};
app.use("/admin", myMiddleware, (req, res) => {
res.sendStatus(401);
});
Notice that I'm creating the cookieParser middleware outside myMiddleware - technically we could also just do return cookieParser()(req, res, next) but recreating the same middleware again and again on every request would be wasteful.
I've also removed the else since the if block returns from the function (guard clause).

setting up a middleware in router.route() in nodejs (express)

what I want it to do.
router.post('/xxxx', authorize , xxxx);
function authorize(req, res, next)
{
if(xxx)
res.send(500);
else
next();
}
I want to check for session in each route.
But since the routers are written in this way.
router.route('/xxx/xxxx').post(function(req, res) {
// blah lah here...
//
});
So how can I set up a middleware that will check for session and I wanted to make things a bit more generic and wanted to have a single authorize function doing a single thing instead of checking in every request.Any suggestions.
Define a middlware function before you define / include your routes, this will avoid you checking for a valid session in every route. See code below for an example on how to do this.
If some routes are public, i.e. they do not require a user to have a valid session then define these BEFORE you 'use' your middlware function
var app = require("express")();
//This is the middleware function which will be called before any routes get hit which are defined after this point, i.e. in your index.js
app.use(function (req, res, next) {
var authorised = false;
//Here you would check for the user being authenticated
//Unsure how you're actually checking this, so some psuedo code below
if (authorised) {
//Stop the user progressing any further
return res.status(403).send("Unauthorised!");
}
else {
//Carry on with the request chain
next();
}
});
//Define/include your controllers
As per your comment, you have two choices with regards to having this middleware affect only some routes, see two examples below.
Option 1 - Declare your specific routes before the middleware.
app.post("/auth/signup", function (req, res, next) { ... });
app.post("/auth/forgotpassword", function (req, res, next) { ... });
//Any routes defined above this point will not have the middleware executed before they are hit.
app.use(function (req, res, next) {
//Check for session (See the middlware function above)
next();
});
//Any routes defined after this point will have the middlware executed before they get hit
//The middlware function will get hit before this is executed
app.get("/someauthorisedrouter", function (req, res, next) { ... });
Option 2 Define your middlware function somewhere and require it where needed
/middleware.js
module.exports = function (req, res, next) {
//Do your session checking...
next();
};
Now you can require it wherever you want it.
/index.js
var session_check = require("./middleware"),
router = require("express").Router();
//No need to include the middlware on this function
router.post("/signup", function (req, res, next) {...});
//The session middleware will be invoked before the route logic is executed..
router.get("/someprivatecontent", session_check, function (req, res, next) { ... });
module.exports = router;
Hope that gives you a general idea of how you can achieve this feature.
Express routers have a neat use() function that lets you define middleware for all routes. router.use('/xxxxx', authorize); router.post('/xxxx', 'xxxx'); should work.
Middleware:
sampleMiddleware.js
export const verifyUser = (req, res, next) => {
console.log('Verified')
next();
}
Routes
import express from 'express';
import { verifyUser } from './sampleMiddleware.js';
const userRoutes = express.Router();
userRoutes.route('/update').put(verifyUser, async function(){
//write your function heere
});
You've probably gotten the answer you need but I'll still drop this
router.route('/xxx/xxxx').get(authorize, function(req, res) {...});

How can I define express middleware for all routes

I am trying to define one global middleware which will work for all routes of my app. I tried some ways but still got some issues.
var _gMDLW = function (req, res, next) {
if(req.route) console.log('Called route ', req.route.path);
next();
}
// Working fine and result on _gMDLW is /route1
app.get('/route1', _gMDLW, function (req, res, next) { return res.sendStatus(200); })
var globalRouter = new express.Router()
// Working fine and result on _gMDLW is /view
globalRouter.route('/view')
.get(_gMDLW, function (req, res, next) { return res.sendStatus(200);})
app.use(globalRouter);
But problem is here
// Error in _gMDLW and getting /list instead of /items/list
var itemRouter = new express.Router()
itemRouter.route('/list')
.get(_gMDLW, function (req, res, next) { return res.sendStatus(200);})
app.use('/items', itemRouter)
Second Question is is there any way to define/add _gMDLW inside app instead of adding in each route something like app.use(_gMDLW) ?
Thank you
You can use app.all() to resolve this issue
Example
app.all('*', _gMDLW);
function _gMDLW(req, res, next) {
if (req.path == '/') return next();// redirect to homepage for guest
next();//authenticated user
}
You can modify it as your requirement

Passport.js - Is it possible to pass a parameter into the router authenticated function?

I would like to pass a certain permission into the authenticated call on routes in Passport.js.
This is what I have now:
app.get('/mypage', app.authenticated, function (req, res, next) {
if (!req.user.hasPermission('myPermission')) {
return res.redirect('/unauthorized');
}
// do stuff
};
var middleware = function(app) {
app.authenticated = function (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
if (req.method == 'GET') {
req.session.returnTo = req.originalUrl;
}
res.redirect('/login');
};
}
module.exports = middleware;
I would instead like to pass the permission into authenticated like this:
app.get('/mypage', app.authenticated('myPermission'), function (req, res, next) {
// do stuff
};
But as far as I can tell, since authenticated gets the parameters it needs automatically, I can't just add a new one.
How can I go about doing this?
You can access req.body values in any of the express middleware.
In your app.authenticated(..) middleware, prior to execution set the value :
req.body['permission'] = 'myPermission'
Use the value of req.body['permission'] for authorisation.

how can I be more specific with express router params

I currently have a few router routes
router.route('/invite/token/:inviteToken')
.get(function (req, res) {
res.status(200).json(req.invite);
});
router.route('/invite/:inviteId')
.get(function (req, res) {
res.status(200).json(req.invite);
});
And the following simple router params:
router.param('inviteToken', function (req, res, next, inviteToken) {
console.log('inviteToken');
// populate req.invite
next();
});
router.param('inviteId', function (req, res, next, inviteId) {
console.log('inviteId');
// populate req.invite
next();
});
However when I try to fetch an invite by token the inviteId param handler is always triggered first with the literal value "token". Is there an issue with the way I've set up the routes and params?
Update 1 For more clarification
Route order definition matters, so the best practice is to go from most specific to most grabby.
app.get('/invite/token/:token', tokenHandler);
app.get('/invite/:inviteId', inviteHandler);
where tokenHandler and inviteHandler are appropriately formatted callback functions.

Resources