The Attribute-Based Access-Control Library let you define five can
access ability:
- Who can? the answer is
subject
- Like RBAC a user can have multiple subjects. - How can it? the answer is
action
- You can defineany
actions you want (scoped). - What can? the answer is
object
- You can defineall
objects you want (scoped). - Where can? the answer is
location
- With IP and CIDR you can find the location of users. - When can it? the answer is
time
- objects availabilities with cron expression and a duration.
Question | RBAC | ABAC |
---|---|---|
Who can access? | ✅ | ✔️ With more options |
How can operate? | ✅ CRUD | ✔️ With more options |
What resource? | ✅ Not Bad At All | ✔️ More control on resource |
Where user can do? | ❌ | ✔️ Supported by IP and CIDR |
When user can do? | ❌ | ✔️ Supported by CRON |
Best structure? | Monolithic Apps | PWA, Restful, GraphQL |
Suitable for? | Small and medium projects | Medium and large projects |
- look at carefully; scan.
- assess or investigate something.
In this library, We scoped action
, object
and subject
which means you can have more control over these attributes.
Note: if you want to have more control over the scoped attributes send at most three character of the first subject
, action
, or object
for example so
or sub|obj
it means subject
and object
are in strict
mode.
npm install --save abacl
Define your user policies as a json array (so you can store it in your database):
import { Policy } from 'abacl';
enum Role {
Admin = 'admin',
User = 'user',
Guest = 'guest',
Manager = 'manager',
}
const policies: Policy<Role>[] = [
{
subject: Role.Admin,
action: 'any',
object: 'all',
},
{
subject: Role.Guest,
action: 'read',
object: 'article:published',
},
{
subject: Role.Guest,
action: 'create:own',
object: 'article:published',
},
{
subject: Role.Manager,
action: 'any',
object: 'article',
},
{
subject: Role.User,
action: 'create:own',
object: 'article',
field: ['*', '!owner'],
location: ['192.168.2.10', '192.168.1.0/24'],
time: [
{
cron_exp: '* * 7 * * *', // from 7 AM
duration: 9 * 60 * 60, // for 9 hours
},
],
},
{
subject: Role.User,
action: 'read:own',
object: 'article',
},
{
subject: Role.User,
action: 'read:shared',
object: 'article',
filter: ['*', '!owner'],
},
{
subject: Role.User,
action: 'delete:own',
object: 'article',
},
{
subject: Role.User,
action: 'update:own',
object: 'article',
field: ['*', '!id', '!owner'],
},
];
Article and User definition objects:
const user = {
id: 1,
subject: Role.User,
ip: '192.168.1.100',
};
const article = {
id: 1,
owner: 'user1',
title: 'title',
content: 'content',
};
Create a new access control object, then get the permission grants:
import AccessControl from 'abacl';
// The `strict` `AccessControlOption` control the scoped functionality
// default strict value is true, you can change it on the `can` method
const ac = new AccessControl(policies, { strict: false });
const permission = await ac.can([user.subject], 'read', 'article');
// change strict mode dynamically, Example:
// const strictPermission = await ac.can([user.subject], 'read', 'article', { strict: true });
/**
* it('should change strict mode dynamically', () => {
* const ac = new AccessControl(policies, { strict: true });
*
* expect(await ac.can([Role.User], 'read', 'article:published').granted).toBeFalsy();
*
* // After changing strict mode
* expect(await ac.can([Role.User], 'read', 'article:published', { strict: false }).granted).toBeTruthy();
* });
*
* */
if (permission.granted) {
// default scope for action and object is `any` and `all`
if (permission.has({ action: 'read:own' })) {
// user has read owned article objects
}
if (permission.has({ action: 'read:shared' })) {
// user can access shared article objects
}
if (permission.has({ object: 'article:published' })) {
// user can access shared article objects
}
// do something ...
// return filtered data based on the permission
const response = await permission.filter(article);
}
Time and location access check example:
import { AccessControl, Permission } from 'abacl';
// default `strict` value is true
const ac = new AccessControl(policies, { strict: true });
const permission = await ac.can([user.subject], 'create', 'article', {
callable: (perm: Permission) => {
return perm.location(user.ip) && perm.time();
},
});
if (permission.granted) {
const inputData = await permission.field(article);
// the `inputData` has not `owner` property
// do something and then return results to user
}
- abacl-redis redis storage driver.
accesscontrol - Role and Attribute based Access Control for Node.js
CASL is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access.