granted
v0.2.3
Published
An object agnostic authorization layer for javascript
Downloads
9
Readme
Granted
An object agnostic authorization layer for javascript. Features both a promise (recommended) and callback api for checking permissions.
account.grants(User, 'admin', function(user) {
return (user.role === 'admin' || this.owner_id === user.id)
});
user.can('admin', account).then(function(user) {
// .. the user is allowed to admin
}).catch(function(e) {
// .. the user is not allowed to admin
});
Introduction:
Sometimes granting access between different objects gets hairy. You have edge cases and lots of ways that permissions can work and things end up being quite a mess.
Granted looks to simplify all of that, taking inspiration from projects like can can in ruby, it defines a few simple methods on an object, allowing us to reliably determine whether one object can perform an action on another.
Let's look at a simple example, say we have three objects, SuperUser
, User
and Document
.
We want a document to be managed by any SuperUser
, but only to a User
if they have
a "role" of "admin", or if they own the account. How would we do that?
First, we would define the granted permissions on the Account
:
var doc = new Document({owner_id: 2, title: 'My Secret Account'});
// Allow any "authenticated" user to read the document.
doc.grants(User, 'read', function(user) {
return user.isAuthenticated();
});
// Allow SuperUsers to do anything to the document.
doc.grants(SuperUser, ['read', 'write', 'destroy'], true);
// Allow Users to do anything to the document if they're
doc.grants(User, ['read', 'write', 'destroy'], function(user) {
// Check that the user's ID matches with the owner_id of the document
return user.id === this.get('owner_id')
});
// Allow anyone to read the metadata about an document, unless the
// object contains an is_robot flag.
doc.grants('readMeta', function(obj) {
return obj.is_robot !== true;
});
Now, we can elsewhere call the can
method on the object we're checking
permissions on:
// Assumes `granted` has been mixed-in to each constructor
var su = new SuperUser();
var authed = new User({authenticated: true});
var user = new User({id: 2});
var visitor = new Generic();
var robot = new Generic({is_robot: true});
su.can('write', doc).then(function(su) {
// ..
})
su.can('destroy', doc).then(function() {
// ..
})
authed.can('read').then(function() {
// true, because the user has been authed.
})
visitor.can('write', doc).catch(function(e) {
// e instanceof granted.Errors.NotGranted
})
// or:
visitor.can('write', doc, function(e, visitor) {
// e instanceof granted.Errors.NotGranted
});
API:
.grants([Constructor | predicate], name, predicate)
Grants the permission specified by name
, (or permissions, if name
is an array)
if the predicate
returns true, resolves with a successful promise, or