node_acl icon indicating copy to clipboard operation
node_acl copied to clipboard

Express middleware and params

Open dottodot opened this issue 8 years ago • 11 comments

I'm a bit confused as to how to get the express middleware to work with params.

The documentation suggests you can add the middleware to route with params i.e.

app.put('/blogs/:id', acl.middleware(), function(req, res, next){…}

however if I add a resource as /blogs/:id I get a insufficient permissions response.

dottodot avatar Jun 06 '16 13:06 dottodot

@dottodot Think you're right and a bit confusing because the description suggest otherwise I'm having the same issues, can't find any reference in the code for such functionality.

The code (https://github.com/OptimalBits/node_acl/blob/master/lib/acl.js#L883) will do a lookup for a bucket called allows_/blogs/1234 and won't find such bucket because it's stored as allows_/blogs/:id

req.route.path contains the pattern but when using sub routers the reference will only contain the part defined in the router.

req.baseUrl + req.route.path instead of req.originalUrl should fix it.

LukevdPalen avatar Jun 17 '16 12:06 LukevdPalen

@dottodot , were you able to get it to work. I am also facing the same issue. I don't understand the solution given by @LukevdPalen .

gundalar avatar Aug 28 '16 18:08 gundalar

@gundalar I just created my own middleware to get round the problem.

dottodot avatar Aug 29 '16 06:08 dottodot

@dottodot Can you share the logic for handling multi-level params such as /feature/:feature/sub-feature/:sub-feature?

cookie-ag avatar Sep 05 '16 05:09 cookie-ag

@serganus I don't actually have anything for multi-level params as I don't have any routes that have them but I think my middleware would work on all routes as I'm checking using req.route.path

function aclCheck(req, res, next) {
    let id = 0;
  if (req.user) {
        id = req.user._id;
  }
    global.acl.isAllowed(id.toString(), '/api' + req.route.path, req.method.toLowerCase(), function(err, allowed) {
        if (allowed) {
      return next();
        }
    res.status(403).json({
      error: 'You are not permitted to perform this action.'
    });
    });
}

dottodot avatar Sep 05 '16 08:09 dottodot

@dottodot, @serganus An another example to make your own acl middleware ;)

import errors from 'feathers-errors'
import Acl from '../acl'

/**
 * @description Check if user has rights on url
 * @param req
 * @param res
 * @param next
 */
export default function (req, res, next) {
        // Make your own fuction to retrieve the user_id (I'm using feathers + jwt + an authentication middleware)
        const user_id = req.feathers.user ? req.feathers.user.id : 'anonymous'
        // Customize your req request to match with your acl resource (I'm using Swagger in this example)
        Acl.isAllowed(user_id, req.swagger.apiPath, req.method.toLowerCase(), (err, result) => {
            if (result) return next()           
            return next(new errors.Forbidden(`NOT_AUTHORIZED`))
        })
}

dimsolution avatar Feb 13 '17 09:02 dimsolution

I solved it with a custom middleware as well for Express 4:

const acl = require('../util/acl.util')

module.exports = resource => (req, res, next) => {
  acl.isAllowed(req.session.userId, resource, req.method.toLowerCase(), (err, allowed) => {
    if (err) return next(err)

    if (!allowed) return res.status(403).send('Insufficient permissions to access resource')
  
    next()
  })
}

Then used in this way:

app.use('/api/users', authMiddleware, aclMiddleware('users'), userRouter)

wilk avatar Feb 16 '17 09:02 wilk

@wilk :)

Hey, can you please elaborate what is authMiddleware & aclMiddleware? because i'm facing problem when i pass these two names.

saurabhh avatar Mar 29 '17 07:03 saurabhh

@saurabhh authMiddleware is just an authentication middleware, where the request is being authenticated, while aclMiddleware is the custom middleware explained in the example above.

wilk avatar Mar 29 '17 22:03 wilk

this is what I use for middleware function

  (req, res, next) => {
      const route = req.path.substr(1)
      const userId = req.user ? req.user.id : 'guest'
      acl.isAllowed(userId, route, req.method.toLowerCase(), (err, result) => {
        if (result) return next()
        return next(err)
      })
    }

Prozi avatar Dec 03 '17 12:12 Prozi

@dottodot Think you're right and a bit confusing because the description suggest otherwise I'm having the same issues, can't find any reference in the code for such functionality.

The code (https://github.com/OptimalBits/node_acl/blob/master/lib/acl.js#L883) will do a lookup for a bucket called allows_/blogs/1234 and won't find such bucket because it's stored as allows_/blogs/:id

~req.route.path contains the pattern but when using sub routers the reference will only contain the part defined in the router. ~

req.baseUrl + req.route.path instead of req.originalUrl should fix it.

For me addition of url = req.baseUrl + req.route.path; here i.e. https://github.com/OptimalBits/node_acl/blob/master/lib/acl.js#L682 in the acl.js solved the issue for the urls with parameters.

@LukevdPalen , I guess this should go into library also as it would handle urls with params. What do you think ?

Thanks, Chaitanya

ChaitanyaBabar avatar May 28 '20 10:05 ChaitanyaBabar