Skip to content

Instantly share code, notes, and snippets.

@TheRusskiy
Last active August 29, 2015 13:55
Show Gist options
  • Save TheRusskiy/8690598 to your computer and use it in GitHub Desktop.
Save TheRusskiy/8690598 to your computer and use it in GitHub Desktop.
NodeJS authorization
auth = (role_middleware_hash)->
return (req, res, next)->
# transform to [{role: function}, {another_role: true}] format:
role_middleware_array = for key, value of role_middleware_hash then obj={}; obj[key]=value; obj
if not req.user? then res.send(403); return; # no user == no access
nextFn = (allowed)->
if allowed is true # previous call allowed access
next()
else if role_middleware_array.length is 0 or allowed is false # all middleware behind, still no explicit access
res.send(403)
else
[[role,fn]]=for key, value of role_middleware_array.splice(0,1)[0] then [key, value];
if req.user.role is role
if typeof(fn) is "function" # User with this role can do stuff only if provided function allows it
fn.call()(req, res, nextFn)
else # User with this role is allowed without any conditions
nextFn(fn)
else
nextFn() # this middleware says nothing, try next
nextFn() # start recursion
module.exports = auth
# Everyone is allowed to see a list of all products
app.get "/api/products", products.index
# Only authenticated users should see product details and create new ones (so guests can't)
app.get "/api/products/:id", auth(), products.show
app.post "/api/products", auth(), products.create
# Only admins and product owners can delete and change product details
app.del "/api/products/:id", auth(admin: true, user: auth.checkOwner), products.delete
app.put "/api/products/:id", auth(admin: true, user: auth.checkOwner), products.update
# Only admins can delete users
app.del "/api/users/:id", auth(admin: true), users.delete
# "checkOwner" is some custom function written in middleware style.
auth.checkOwner = ()-> (req, res, next)->
getResource(req).findOne {_id: req.params.id}, (err, resource)->
# toString() is used because mongoose key doesn't equal to otherkey just like that
if resource._creator.toString() is req.user._id.toString()
next(true)
else
res.send(403) # or next(false)
# It can allow action by next(true), it can forbid it by res.send(403) or it can let next middleware decide by next()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment