Vartan Arabyan
Vartan Arabyan

Reputation: 3073

Creating a expressjs middleware that accepts parameters

I am trying to create a middleware that can accept parameters. How can this be done?

example

app.get('/hasToBeAdmin', HasRole('Admin'), function(req,res){

})

HasRole = function(role, req, res, next){
   if (role != user.role) {
      res.redirect('/NotInRole');
   }

   next();
}

Upvotes: 153

Views: 68363

Answers (8)

Anvesh Damuluri
Anvesh Damuluri

Reputation: 21

Here is my simple solution for this. Basically we cannot pass arguments to middleware but using wrapper function we can achieve this.

const restrictTo = (...roles) => {
   return (req, res, next) => {
    // roles are : ['admin', 'user'], role : req.user.role
   if (!roles.includes(req.user.role)) // I am taking role from req.user you can get it from model
      {
       return new Error('You dont have permission to delete the tour', 404)
      }
   next();
  }
};
Call it like ...

router.delete(restrictTo('admin', 'user'), handler);

Upvotes: 2

Al Fahad
Al Fahad

Reputation: 2578

After following documentation from here, I was able to solve this issue, I made this middleware and passed the array of role_ids that were allowed to access the route

exports.authorize = function (roles) {
  return function (req, res, next) {
    console.log(roles)
    if (roles?.includes(req.user.role_id)) {
      return next()
    } else {
      return res.status(403).send({
        error: "Not Authorized to access this route"
      })
    }
  }
}

and called it in routes file like this

myRouter.get("/", authorize([USER_ROLES.OPERATOR]), getSomething);

if you are wondoring what user role is its just like an enum

const USER_ROLES = Object.freeze({
  ADMIN: 1,
  HOST: 2,
  OPERATOR: 3,
  LOCKER_ADMIN: 4,
  MERCHANT: 5,
  CUSTOMER: 6,
  COURIER: 7,
  ECOMMERCE: 8
});

Upvotes: 2

Ricardo Alves
Ricardo Alves

Reputation: 561

Since we are in 2021 why not using an ES6 syntax?... Using NodeJS v14.16.1 the example below works like a charm :-)

With express routers

const someFunc = ({ option1, option2 }) =>
 router.get("/", (req, res, next) => {
    
 // code
    
 next();
});

module.exports = someFunc;

or

const someFunc = ({ option1, option2 }) =>
     (req, res, next) => {
        
     // code
        
     next();
    };
    
 module.exports = someFunc;

... Then call it like:

const someFunc = require('./middlewares/someFunc.js');
app.use(someFunc({option1: 'test', option2: false ));

Upvotes: 2

jarraga
jarraga

Reputation: 437

I use this solution. I recieve a jwt token in body req, and get role information from there

//roleMiddleware.js

const checkRole = role => {
    
    return (req, res, next) => {
        if (req.role == role) {
            console.log(`${role} role granted`)
            next()
        } else {
            res.status(401).send({ result: 'error', message: `No ${role} permission granted` })
        }
    }
}

module.exports = { checkRole }

So first I use auth middleware to know if is a valid user, and then the role middleware to know if user have access to the api route

// router.js

router.post('/v1/something-protected', requireAuth, checkRole('commercial'), (req, res) => {
    // do what you want...
})

I hope to be useful

Upvotes: 12

zevero
zevero

Reputation: 2412

Alternatively if you do not have too many cases or if role is NOT a string:

function HasRole(role) {
  return function (req, res, next) {
    if (role !== req.user.role) res.redirect(/* ... */);
    else next();
  }
}

var middlware_hasRoleAdmin = HasRole('admin'); // define router only once

app.get('/hasToBeAdmin', middlware_hasRoleAdmin, function (req, res) {

})

Upvotes: 8

chovy
chovy

Reputation: 75814

app.get('/hasToBeAdmin', (req, res, next) => {
  hasRole(req, res, next, 'admin');
}, (req,res) => { 
    // regular route 
});

const hasRole = (req, res, next, role) => {
   if(role != user.role){
      res.redirect('/NotInRole');
   }
   next();
};

Upvotes: 27

asdf
asdf

Reputation: 1032

If you have various permissions levels you could structure them like this:

const LEVELS = Object.freeze({
  basic: 1,
  pro: 2,
  admin: 3
});

/**
 *  Check if user has the required permission level
 */
module.exports = (role) => {
  return (req, res, next) => {
    if (LEVELS[req.user.role] < LEVELS[role]) return res.status(401).end();
    return next();
  }
}

Upvotes: 3

Jonathan Ong
Jonathan Ong

Reputation: 20345

function HasRole(role) {
  return function(req, res, next) {
    if (role !== req.user.role) res.redirect(...);
    else next();
  }
}

I also want to make sure that I don't make multiple copies of the same function:

function HasRole(role) {
  return HasRole[role] || (HasRole[role] = function(req, res, next) {
    if (role !== req.user.role) res.redirect(...);
    else next();
  })
}

Upvotes: 212

Related Questions