@prostojs/arbac v0.0.2
@prostojs/arbac
Advanced Role-Based Access Control (ARBAC) for Node.js, designed to facilitate the implementation of complex access control systems in a straightforward and intuitive manner. With @prostojs/arbac, you can define roles, resources, and rules with dynamic scopes based on user attributes, enabling fine-grained access control tailored to your application's specific needs.
Features
- Define roles with customizable rules.
- Control access based on user attributes.
- Support for dynamic scopes to fine-tune access control.
- Wildcard support in resource names and actions for flexible rule definition.
- Easy integration with any Node.js application.
Installation
Install @prostojs/arbac using npm:
npm install @prostojs/arbacOr using yarn:
yarn add @prostojs/arbacQuick Start
Below is a quick example to demonstrate the basic setup and usage:
import { Arbac } from '@prostojs/arbac';
// Define your user attributes and scope types
interface UserAttributes {
userId: string;
departmentId: string[];
}
interface AccessScope {
departmentIds: string[];
}
// Initialize ARBAC
const arbac = new Arbac<UserAttributes, AccessScope>();
arbac.registerRole({
id: 'employee',
rules: [
{
action: 'read',
resource: 'com.resource.db.leads',
scope: userAttrs => ({ departmentIds: userAttrs.departmentId }),
},
],
});
// Define a user
const user = {
id: 'user123',
roles: ['employee'],
attrs: async (userId) => ({
userId,
departmentId: ['dept1', 'dept2'],
}),
};
// Evaluate access
const result = await arbac.evaluate({
resource: 'com.resource.db.leads',
action: 'read',
}, user);
console.log(result); // { allowed: true, scopes: [{ departmentIds: ['dept1', 'dept2'] }] }Scopes
Scopes allow defining fine-grained access control rules by dynamically assigning context-based restrictions. When a role grants access to a resource, it can specify a scope function that derives additional constraints based on the user's attributes. These scopes are evaluated dynamically and returned as part of the evaluation result.
For example, a role may grant access to a resource but restrict access to specific departments the user belongs to:
arbac.registerRole({
id: 'com.role.sales',
rules: [
{
action: 'read',
resource: 'com.resource.db.leads',
scope: userAttrs => ({ departmentIds: userAttrs.departmentId }),
},
],
});If a user with com.role.sales has { departmentId: ['dept1', 'dept2'] }, the evaluation will return:
{
"allowed": true,
"scopes": [{ "departmentIds": ["dept1", "dept2"] }]
}Scopes are useful when access should be limited based on user-specific attributes such as organizational structure, project assignments, or other contextual factors.
Role and Resource Management
Registering Roles
arbac.registerRole({
id: 'com.role.editor',
rules: [
{
action: 'edit',
resource: 'com.resource.docs.*',
},
{
action: 'delete',
effect: 'deny',
resource: 'com.resource.docs.archived',
},
],
});Resource Registration
Resources are automatically registered when evaluated. However, you can manually register them if needed:
arbac.registerResource('com.resource.docs.article');Evaluation
const result = await arbac.evaluate(
{
action: 'edit',
resource: 'com.resource.docs.article',
},
{
id: 'user123',
roles: ['com.role.editor'],
attrs: { userId: 'user123', departmentId: ['dept1', 'dept2'] },
}
);
console.log(result); // { allowed: true }Wildcards in Rules
*matches any single segment (e.g.,com.resource.db.*allows access tocom.resource.db.userbut notcom.resource.api.user).**matches multiple segments (e.g.,com.resource.**allows access tocom.resource.db.userandcom.resource.api.user).
Example with Wildcards
arbac.registerRole({
id: 'admin',
rules: [
{
action: '*',
resource: 'com.resource.db.*',
},
{
action: 'delete',
effect: 'deny',
resource: 'com.resource.db.sensitiveData',
},
{
action: '*',
resource: 'com.resource.**',
},
],
});API Reference
Arbac<TUserAttrs, TScope>
Main class to manage roles, resources, and access evaluation.
constructor()
Initializes the ARBAC system.
registerRole(role: TArbacRole<TUserAttrs, TScope>): void
Registers a new role with the ARBAC system.
registerResource(resource: string): void
Registers a new resource. This is optional as resources are auto-registered when evaluated.
async evaluate(opts: { resource: string; action: string }, user: { id: string; roles: string[]; attrs: TUserAttrs | ((userId: string) => Promise<TUserAttrs>) }): Promise<TArbacEvalResult<TScope>>
Evaluates access for a given user, resource, and action. Returns an object indicating whether access is allowed and any applicable scopes.
Testing
Run tests using vitest:
npm testContributing
Contributions are welcome! Please feel free to submit a pull request or open an issue to discuss proposed changes or enhancements.
License
This project is licensed under the MIT License.