node_acl
node_acl copied to clipboard
Express middleware and params
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 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.
@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 I just created my own middleware to get round the problem.
@dottodot Can you share the logic for handling multi-level params such as /feature/:feature/sub-feature/:sub-feature
?
@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, @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`))
})
}
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 :)
Hey, can you please elaborate what is authMiddleware & aclMiddleware? because i'm facing problem when i pass these two names.
@saurabhh authMiddleware
is just an authentication middleware, where the request is being authenticated, while aclMiddleware
is the custom middleware explained in the example above.
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)
})
}
@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 asallows_/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 ofreq.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