Convert Figma logo to code with AI

OptimalBits logonode_acl

Access control lists for node applications

2,618
369
2,618
148

Top Related Projects

An authorization library that supports access control models like ACL, RBAC, ABAC in Node.js and Browser

Role and Attribute based Access Control for Node.js

1,697

An unopinionated authentication library for building Node.js APIs.

66,731

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀

Quick Overview

Node ACL is a flexible and powerful access control list (ACL) middleware for Node.js applications. It provides a simple and intuitive API for managing user permissions and access control within your application.

Pros

  • Flexible and Customizable: Node ACL allows you to define complex permission structures and access control policies, making it suitable for a wide range of applications.
  • Easy to Integrate: The library is designed to be easily integrated into existing Node.js projects, with a straightforward API and minimal setup required.
  • Robust and Reliable: Node ACL is well-maintained, with a large community of contributors and a solid track record of stability and reliability.
  • Extensive Documentation: The project has comprehensive documentation, including detailed examples and use cases, making it easy for developers to get started and understand the library's capabilities.

Cons

  • Learning Curve: While the API is relatively simple, the flexibility and power of Node ACL may require some initial effort to fully understand and configure for complex use cases.
  • Performance Overhead: Depending on the size and complexity of your permission structure, the ACL management may introduce some performance overhead, which may need to be considered for high-traffic applications.
  • Limited Caching: The library does not provide built-in caching mechanisms, which may require additional effort to implement for performance-critical applications.
  • Dependency on External Stores: Node ACL relies on external data stores (e.g., Redis, MongoDB) for storing ACL data, which may add complexity and introduce additional points of failure.

Code Examples

Here are a few examples of how to use Node ACL:

  1. Defining Roles and Permissions:
const acl = require('acl');
acl = new acl(new acl.memoryBackend());

acl.allow('admin', ['users', 'articles'], ['create', 'read', 'update', 'delete']);
acl.allow('user', 'articles', ['read']);
  1. Checking User Permissions:
acl.isAllowed('admin', 'articles', 'create', (err, allowed) => {
  if (err) throw err;
  console.log(allowed); // true
});
  1. Middleware Integration:
const express = require('express');
const app = express();
const acl = require('acl');
acl = new acl(new acl.memoryBackend());

app.use((req, res, next) => {
  acl.middleware(req, res, next);
});

app.get('/admin/dashboard', acl.middleware(2, 'admin'), (req, res) => {
  res.send('Admin dashboard');
});
  1. Handling Hierarchical Permissions:
acl.addUserRoles('john', 'user');
acl.addRoleParents('admin', 'user');

acl.isAllowed('john', 'articles', 'read', (err, allowed) => {
  if (err) throw err;
  console.log(allowed); // true (inherited from 'user' role)
});

Getting Started

To get started with Node ACL, follow these steps:

  1. Install the library using npm:
npm install acl
  1. Import the library and create a new ACL instance:
const acl = require('acl');
acl = new acl(new acl.memoryBackend());
  1. Define your roles and permissions:
acl.allow('admin', ['users', 'articles'], ['create', 'read', 'update', 'delete']);
acl.allow('user', 'articles', ['read']);
  1. Integrate the ACL middleware with your Express.js application:
const express = require('express');
const app = express();

app.use((req, res, next) => {
  acl.middleware(req, res, next);
});

app.get('/admin/dashboard', acl.middleware(2, 'admin'), (req, res) => {
  res.send('Admin dashboard');
});
  1. Check user permissions and enforce access control:
acl.isAll

Competitor Comparisons

An authorization library that supports access control models like ACL, RBAC, ABAC in Node.js and Browser

Pros of node-casbin

  • Flexible and Extensible: node-casbin supports a wide range of access control models, including RBAC, ABAC, and more, making it a versatile choice for various access control requirements.
  • Persistence Support: node-casbin provides built-in support for different data storage options, including in-memory, file-based, and database-backed persistence.
  • Powerful Enforcement: node-casbin offers a robust enforcement mechanism, allowing you to easily integrate access control into your application.

Cons of node-casbin

  • Steeper Learning Curve: Compared to node_acl, node-casbin may have a slightly steeper learning curve due to its more complex configuration and policy management.
  • Larger Codebase: node-casbin has a larger codebase and dependencies, which may result in a larger project footprint and potentially slower initial setup.

Code Comparison

node_acl:

acl.allow('admin', 'blogs', ['create', 'read', 'update', 'delete']);
acl.allow('user', 'blogs', ['read']);

acl.can('admin', 'blogs', 'create', function(err, allowed) {
  console.log(allowed); // true
});

node-casbin:

const { newEnforcer } = require('casbin');

const enforcer = await newEnforcer('examples/rbac_model.conf', 'examples/rbac_policy.csv');
enforcer.addPolicy('alice', 'data1', 'read');
enforcer.addPolicy('bob', 'data2', 'write');

const isAllowed = await enforcer.enforce('alice', 'data1', 'read');
console.log(isAllowed); // true

Role and Attribute based Access Control for Node.js

Pros of accesscontrol

  • More flexible and granular permission definitions
  • Supports attribute-based access control (ABAC)
  • Lightweight with no dependencies

Cons of accesscontrol

  • Less mature and less widely adopted
  • Limited built-in storage options
  • Steeper learning curve for complex scenarios

Code Comparison

node_acl:

acl.allow('user', 'blogs', 'view')
acl.isAllowed('joed', 'blogs', 'view', function(err, res){
    if(res){
        console.log("User joed is allowed to view blogs");
    }
});

accesscontrol:

const ac = new AccessControl();
ac.grant('user').readAny('blog');
const permission = ac.can('user').readAny('blog');
if (permission.granted) {
    console.log("User is allowed to read any blog");
}

Both libraries provide ACL functionality, but accesscontrol offers more granular control and supports ABAC. node_acl has a simpler API and is more established, while accesscontrol provides greater flexibility at the cost of a steeper learning curve. The choice between them depends on the specific requirements of your project and the level of access control granularity needed.

1,697

An unopinionated authentication library for building Node.js APIs.

Pros of permit

  • Simpler API with a more intuitive and modern design
  • Built-in support for async/await and Promises
  • Lightweight and minimal dependencies

Cons of permit

  • Less mature and less widely adopted compared to node_acl
  • Fewer built-in features and integrations
  • Limited documentation and community support

Code Comparison

permit:

const permit = new Permit()

permit.check(user, 'posts:create')
permit.grant('admin', 'posts:*')
permit.revoke('user', 'posts:delete')

node_acl:

acl.allow('admin', 'posts', '*')
acl.removeAllow('user', 'posts', 'delete')
acl.isAllowed('user', 'posts', 'create', (err, allowed) => {
  if (allowed) {
    // User can create posts
  }
})

Both libraries provide similar functionality for managing access control, but permit offers a more modern and streamlined API. node_acl, on the other hand, has been around longer and provides more extensive features and integrations. The choice between the two depends on the specific requirements of your project, such as the need for advanced features, community support, or a more lightweight solution.

66,731

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀

Pros of Nest

  • Full-featured framework for building scalable server-side applications
  • Built-in support for TypeScript and dependency injection
  • Extensive ecosystem with modules for various functionalities

Cons of Nest

  • Steeper learning curve due to its comprehensive nature
  • Potentially overkill for simple applications or microservices
  • Opinionated architecture may not suit all project requirements

Code Comparison

Nest (Controller example):

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}

node_acl (ACL setup example):

var acl = new acl(new acl.memoryBackend());
acl.allow('guest', 'blogs', 'view');
acl.allow('member', 'blogs', ['edit', 'view', 'delete']);

Summary

Nest is a comprehensive framework for building server-side applications, offering a wide range of features and strong TypeScript support. It's well-suited for large, complex projects but may be excessive for simpler applications. node_acl, on the other hand, is a focused library for implementing Access Control Lists in Node.js applications. It's more lightweight and easier to integrate into existing projects, but lacks the full-featured nature of Nest. The choice between the two depends on the specific requirements of your project and the desired level of abstraction and functionality.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

NODE ACL - Access Control Lists for Node

This module provides a minimalistic ACL implementation inspired by Zend_ACL.

When you develop a web site or application you will soon notice that sessions are not enough to protect all the available resources. Avoiding that malicious users access other users content proves a much more complicated task than anticipated. ACL can solve this problem in a flexible and elegant way.

Create roles and assign roles to users. Sometimes it may even be useful to create one role per user, to get the finest granularity possible, while in other situations you will give the asterisk permission for admin kind of functionality.

A Redis, MongoDB and In-Memory based backends are provided built-in in the module. There are other third party backends such as knex based, firebase and elasticsearch. There is also an alternative memory backend that supports regexps.

Follow manast for news and updates regarding this library.

Status

BuildStatus Dependency Status devDependency Status

Features

  • Users
  • Roles
  • Hierarchies
  • Resources
  • Express middleware for protecting resources.
  • Robust implementation with good unit test coverage.

Installation

Using npm:

npm install acl

Documentation

Examples

Create your acl module by requiring it and instantiating it with a valid backend instance:

var acl = require('acl');

// Using redis backend
acl = new acl(new acl.redisBackend(redisClient, prefix));

// Or Using the memory backend
acl = new acl(new acl.memoryBackend());

// Or Using the mongodb backend
acl = new acl(new acl.mongodbBackend(dbInstance, prefix));

All the following functions return a promise or optionally take a callback with an err parameter as last parameter. We omit them in the examples for simplicity.

Create roles implicitly by giving them permissions:

// guest is allowed to view blogs
acl.allow('guest', 'blogs', 'view')

// allow function accepts arrays as any parameter
acl.allow('member', 'blogs', ['edit', 'view', 'delete'])

Users are likewise created implicitly by assigning them roles:

acl.addUserRoles('joed', 'guest')

Hierarchies of roles can be created by assigning parents to roles:

acl.addRoleParents('baz', ['foo', 'bar'])

Note that the order in which you call all the functions is irrelevant (you can add parents first and assign permissions to roles later)

acl.allow('foo', ['blogs', 'forums', 'news'], ['view', 'delete'])

Use the wildcard to give all permissions:

acl.allow('admin', ['blogs', 'forums'], '*')

Sometimes is necessary to set permissions on many different roles and resources. This would lead to unnecessary nested callbacks for handling errors. Instead use the following:

acl.allow([
    {
        roles:['guest', 'member'],
        allows:[
            {resources:'blogs', permissions:'get'},
            {resources:['forums', 'news'], permissions:['get', 'put', 'delete']}
        ]
    },
    {
        roles:['gold', 'silver'],
        allows:[
            {resources:'cash', permissions:['sell', 'exchange']},
            {resources:['account', 'deposit'], permissions:['put', 'delete']}
        ]
    }
])

You can check if a user has permissions to access a given resource with isAllowed:

acl.isAllowed('joed', 'blogs', 'view', function(err, res){
    if(res){
        console.log("User joed is allowed to view blogs")
    }
})

Of course arrays are also accepted in this function:

acl.isAllowed('jsmith', 'blogs', ['edit', 'view', 'delete'])

Note that all permissions must be fulfilled in order to get true.

Sometimes is necessary to know what permissions a given user has over certain resources:

acl.allowedPermissions('james', ['blogs', 'forums'], function(err, permissions){
    console.log(permissions)
})

It will return an array of resource:[permissions] like this:

[{'blogs' : ['get', 'delete']},
 {'forums':['get', 'put']}]

Finally, we provide a middleware for Express for easy protection of resources.

acl.middleware()

We can protect a resource like this:

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

The middleware will protect the resource named by req.url, pick the user from req.session.userId and check the permission for req.method, so the above would be equivalent to something like this:

acl.isAllowed(req.session.userId, '/blogs/12345', 'put')

The middleware accepts 3 optional arguments, that are useful in some situations. For example, sometimes we cannot consider the whole url as the resource:

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

In this case the resource will be just the three first components of the url (without the ending slash).

It is also possible to add a custom userId or check for other permissions than the method:

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

Methods

addUserRoles( userId, roles, function(err) )

Adds roles to a given user id.

Arguments

    userId   {String|Number} User id.
    roles    {String|Array} Role(s) to add to the user id.
    callback {Function} Callback called when finished.

removeUserRoles( userId, roles, function(err) )

Remove roles from a given user.

Arguments

    userId   {String|Number} User id.
    roles    {String|Array} Role(s) to remove to the user id.
    callback {Function} Callback called when finished.

userRoles( userId, function(err, roles) )

Return all the roles from a given user.

Arguments

    userId   {String|Number} User id.
    callback {Function} Callback called when finished.

roleUsers( rolename, function(err, users) )

Return all users who has a given role.

Arguments

    rolename   {String|Number} User id.
    callback {Function} Callback called when finished.

hasRole( userId, rolename, function(err, hasRole) )

Return boolean whether user has the role

Arguments

    userId   {String|Number} User id.
    rolename {String|Number} role name.
    callback {Function} Callback called when finished.

addRoleParents( role, parents, function(err) )

Adds a parent or parent list to role.

Arguments

    role     {String} Child role.
    parents  {String|Array} Parent role(s) to be added.
    callback {Function} Callback called when finished.

removeRoleParents( role, parents, function(err) )

Removes a parent or parent list from role.

If parents is not specified, removes all parents.

Arguments

    role     {String} Child role.
    parents  {String|Array} Parent role(s) to be removed [optional].
    callback {Function} Callback called when finished [optional].

removeRole( role, function(err) )

Removes a role from the system.

Arguments

    role     {String} Role to be removed
    callback {Function} Callback called when finished.

### removeResource( resource, function(err) )

Removes a resource from the system

Arguments

    resource {String} Resource to be removed
    callback {Function} Callback called when finished.

allow( roles, resources, permissions, function(err) )

Adds the given permissions to the given roles over the given resources.

Arguments

    roles       {String|Array} role(s) to add permissions to.
    resources   {String|Array} resource(s) to add permisisons to.
    permissions {String|Array} permission(s) to add to the roles over the resources.
    callback    {Function} Callback called when finished.

allow( permissionsArray, function(err) )

Arguments

    permissionsArray {Array} Array with objects expressing what permissions to give.
       [{roles:{String|Array}, allows:[{resources:{String|Array}, permissions:{String|Array}]]

    callback         {Function} Callback called when finished.

removeAllow( role, resources, permissions, function(err) )

Remove permissions from the given roles owned by the given role.

Note: we loose atomicity when removing empty role_resources.

Arguments

    role        {String}
    resources   {String|Array}
    permissions {String|Array}
    callback    {Function}

allowedPermissions( userId, resources, function(err, obj) )

Returns all the allowable permissions a given user have to access the given resources.

It returns an array of objects where every object maps a resource name to a list of permissions for that resource.

Arguments

    userId    {String|Number} User id.
    resources {String|Array} resource(s) to ask permissions for.
    callback  {Function} Callback called when finished.

isAllowed( userId, resource, permissions, function(err, allowed) )

Checks if the given user is allowed to access the resource for the given permissions (note: it must fulfill all the permissions).

Arguments

    userId      {String|Number} User id.
    resource    {String} resource to ask permissions for.
    permissions {String|Array} asked permissions.
    callback    {Function} Callback called with the result.

areAnyRolesAllowed( roles, resource, permissions, function(err, allowed) )

Returns true if any of the given roles have the right permissions.

Arguments

    roles       {String|Array} Role(s) to check the permissions for.
    resource    {String} resource to ask permissions for.
    permissions {String|Array} asked permissions.
    callback    {Function} Callback called with the result.

whatResources(role, function(err, {resourceName: [permissions]})

Returns what resources a given role has permissions over.

Arguments

    role        {String|Array} Roles
    callback    {Function} Callback called with the result.

whatResources(role, permissions, function(err, resources) )

Returns what resources a role has the given permissions over.

Arguments

    role        {String|Array} Roles
    permissions {String|Array} Permissions
    callback    {Function} Callback called with the result.

middleware( [numPathComponents, userId, permissions] )

Middleware for express.

To create a custom getter for userId, pass a function(req, res) which returns the userId when called (must not be async).

Arguments

    numPathComponents {Number} number of components in the url to be considered part of the resource name.
    userId            {String|Number|Function} the user id for the acl system (defaults to req.session.userId)
    permissions       {String|Array} the permission(s) to check for (defaults to req.method.toLowerCase())

backend( db, [prefix] )

Creates a backend instance. All backends except Memory require driver or database instance. useSingle is only applicable to the MongoDB backend.

Arguments

    db        {Object} Database instance
    prefix    {String} Optional collection prefix
    useSingle     {Boolean} Create one collection for all resources (defaults to false)
var mongodb = require('mongodb');
mongodb.connect("mongodb://127.0.0.1:27017/acltest", function(error, db) {
  var mongoBackend = new acl.mongodbBackend(db, 'acl_');
});

Creates a new MongoDB backend using database instance db.

var client = require('redis').createClient(6379, '127.0.0.1', {no_ready_check: true});
var redisBackend = new acl.redisBackend(client);

Creates a new Redis backend using Redis client client.

Tests

Run tests with npm (requires mocha):

 npm test

Future work

  • Support for denials (deny a role a given permission)

License

(The MIT License)

Copyright (c) 2011-2013 Manuel Astudillo manuel@optimalbits.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

NPM DownloadsLast 30 Days