@anishpras/rbac

中文文档
2.1.1发布于 2025/03/28MITTypeScriptESM + CJS零依赖近 30 天下载 2949

A fast, flexible, and production-ready role-based access control (RBAC) system for JavaScript/TypeScript applications.

原始使用文档
文档目录24 节
  1. Features
  2. Installation
  3. Quick Start
  4. Express.js Middleware Example
  5. Understanding Role Hierarchy (Role Inheritance)
  6. Dynamic Permission Updates
  7. Policy Evaluation
  8. Query Available Permissions and Resources
  9. Best Practices
  10. 1. Use Constants for Roles, Resources and Permissions
  11. 2. Non-strict Mode in Production
  12. 3. Enable Caching
  13. 4. Properly Set Up Role Hierarchy
  14. 5. Use Custom Logger
  15. 6. Implement Resource Ownership
  16. Security Features
  17. Advanced Examples
  18. API Reference
  19. RBACManager
  20. RBACBuilder
  21. Build and Development
  22. Building the Project
  23. Minification
  24. License

@anishpras/rbac: Role and Attribute Based Access Control

A fast, flexible, and production-ready role-based access control (RBAC) system for JavaScript/TypeScript applications.

Features

  • 🚀 Fast and efficient: Optimized for speed with LRU caching
  • 🔒 Type-safe: Full TypeScript support
  • 🧩 Flexible: Define custom roles, resources, and permissions
  • 🔄 Role hierarchy: Support for role inheritance with robust cycle detection
  • 🛠️ Middleware support: Ready for Express.js and other frameworks
  • 📝 Fluent API: Intuitive builder pattern for configuration
  • 📊 Runtime updates: Modify permissions without restarting
  • 🧪 Strict mode: Optional throw on unrecognized roles/resources
  • 📈 Scalable: Designed for large-scale applications

Installation

npm install @anishpras/rbac
# or
yarn add @anishpras/rbac
# or
pnpm add @anishpras/rbac

Quick Start

import { RBACManager, RBACBuilder } from '@anishpras/rbac';

// Create a configuration using the builder
const config = new RBACBuilder()
  .role('ADMIN', 'Administrator with full access')
    .grantFullAccess('Products')
    .grantFullAccess('News')
    .grantFullAccess('Bookings')
    .done()
  .role('EDITOR', 'Editor with limited access')
    .forResource('Products').grantAll().and()
    .forResource('News').grantAll().and()
    .forResource('Bookings').grantReadOnly().done()
  .setDefaultRole('EDITOR')
  .build();

// Create the RBAC manager
const rbac = new RBACManager(config, {
  cache: {
    enabled: true,
    maxSize: 1000,
    ttl: 60 * 1000 // 1 minute
  },
  strict: false, // Avoid runtime errors in production
  logger: {
    debug: (msg) => console.debug(`[RBAC] ${msg}`),
    info: (msg) => console.info(`[RBAC] ${msg}`),
    warn: (msg) => console.warn(`[RBAC] ${msg}`),
    error: (msg) => console.error(`[RBAC] ${msg}`)
  }
});

// Check permissions
const user = {
  id: 1,
  roles: ['EDITOR']
};

// Check if a user can create a product
if (rbac.userCan(user, 'Products', 'CREATE')) {
  // User can create products
}

// Check if a user can update a booking
if (rbac.userCan(user, 'Bookings', 'UPDATE')) {
  // User cannot update bookings
}

Express.js Middleware Example

import express from 'express';
import { RBACManager } from '@anishpras/rbac';

const app = express();
const rbac = new RBACManager(config);

// Middleware to protect routes
app.get(
  '/api/products',
  rbac.middleware({
    getUserRoles: (req) => req.user.roles,
    resource: 'Products',
    permission: 'READ',
    onDenied: (req, res) => {
      res.status(403).json({ error: 'Access denied' });
    }
  }),
  (req, res) => {
    // Handle the request
  }
);

// Dynamic permission based on HTTP method
app.all(
  '/api/bookings/:id',
  rbac.middleware({
    getUserRoles: (req) => req.user.roles,
    resource: 'Bookings',
    permission: (req) => {
      // Map HTTP method to permission
      switch (req.method) {
        case 'GET': return 'READ';
        case 'POST': return 'CREATE';
        case 'PUT': case 'PATCH': return 'UPDATE';
        case 'DELETE': return 'DELETE';
        default: return 'READ';
      }
    },
    onDenied: (req, res) => {
      res.status(403).json({ 
        error: 'Access denied',
        message: `You don't have permission to ${req.method} bookings` 
      });
    }
  }),
  (req, res) => {
    // Handle the request
  }
);

Understanding Role Hierarchy (Role Inheritance)

The role hierarchy feature allows roles to inherit permissions from other roles. This is one of the most powerful but sometimes confusing aspects of the library.

// Define role hierarchy
rbac.setRoleHierarchy({
  'EDITOR': ['ADMIN'],  // EDITOR inherits all permissions from ADMIN
  'VIEWER': ['EDITOR']  // VIEWER inherits all permissions from EDITOR
});

Important Clarification on Role Hierarchy:

In the role hierarchy configuration:

  • The key is the child role (the one inheriting permissions)
  • The array values are the parent roles (the ones being inherited from)

This means:

  • 'EDITOR': ['ADMIN'] means that EDITOR inherits permissions from ADMIN, not the other way around
  • 'VIEWER': ['EDITOR'] means VIEWER inherits from EDITOR (and transitively from ADMIN too)

Think of it like this:

'CHILD_ROLE': ['PARENT_ROLE_1', 'PARENT_ROLE_2']

Let's look at a more complete example to illustrate how role hierarchy works:

// Define role hierarchy with more complex relationships
rbac.setRoleHierarchy({
  // Store roles inherit from more general roles
  'STORE_MANAGER': ['ADMIN'],      // Store Manager inherits from Admin
  'STORE_CLERK': ['STORE_MANAGER'], // Store Clerk inherits from Store Manager
  
  // Content roles also inherit
  'CONTENT_EDITOR': ['ADMIN'],     // Content Editor inherits from Admin
  'CONTENT_VIEWER': ['CONTENT_EDITOR'], // Content Viewer inherits from Content Editor
  
  // Special case: dual inheritance
  'SUPERVISOR': ['STORE_MANAGER', 'CONTENT_EDITOR'] // Inherits from both roles
});

// Let's test some permissions
console.log(rbac.can('STORE_CLERK', 'Products', 'READ')); // true if STORE_MANAGER has this permission
console.log(rbac.can('SUPERVISOR', 'Content', 'PUBLISH')); // true if either parent role has this permission

The library automatically handles transitive inheritance and detects circular references to prevent infinite loops.

Dynamic Permission Updates

You can modify permissions at runtime without restarting your application:

// Add a new role
rbac.addRole('MANAGER', {
  description: 'Manager role',
  permissions: {
    'Products': ['READ', 'UPDATE'],
    'Bookings': ['READ', 'UPDATE', 'CREATE']
  }
});

// Grant new permissions
rbac.grant('EDITOR', 'Reports', ['READ']);

// Revoke permissions
rbac.revoke('EDITOR', 'Bookings', ['DELETE']);

// Revoke all permissions on a resource
rbac.revoke('EDITOR', 'Bookings');

// Remove a role entirely
rbac.removeRole('GUEST');

// Update the entire configuration
rbac.updateConfig(newConfig);

Remember to clear the cache after making permission changes (the built-in methods like grant() and revoke() handle this automatically):

// Manually clear the cache when needed
rbac.clearCache();

Policy Evaluation

You can evaluate policies directly:

const policyResult = rbac.evaluatePolicy({
  role: 'EDITOR',
  resource: 'Products',
  permission: 'UPDATE'
});

console.log(policyResult.allowed); // boolean
console.log(policyResult.reason);  // explanation string

Query Available Permissions and Resources

// Get all permissions a role has on a resource
const permissions = rbac.getPermissions('EDITOR', 'Products');
// Returns: ['CREATE', 'READ', 'UPDATE', 'DELETE']

// Get all resources a role has access to
const resources = rbac.getResources('ADMIN');
// Returns: ['Products', 'News', 'Bookings', ...]

// Get all roles in the system
const roles = rbac.getRoles();
// Returns: ['ADMIN', 'EDITOR', 'VIEWER', ...]

// Get cache statistics
const cacheStats = rbac.getCacheStats();
// Returns: { enabled: true, size: 42 }

Best Practices

1. Use Constants for Roles, Resources and Permissions

Define constants to prevent typos and ensure consistency:

// Define constants
const ROLES = {
  ADMIN: 'ADMIN',
  EDITOR: 'EDITOR',
  VIEWER: 'VIEWER'
} as const;

const RESOURCES = {
  PRODUCTS: 'Products',
  USERS: 'Users',
  ORDERS: 'Orders'
} as const;

const PERMISSIONS = {
  CREATE: 'CREATE',
  READ: 'READ',
  UPDATE: 'UPDATE',
  DELETE: 'DELETE'
} as const;

// Use constants in your code
rbac.grant(ROLES.EDITOR, RESOURCES.PRODUCTS, [PERMISSIONS.READ, PERMISSIONS.UPDATE]);

2. Non-strict Mode in Production

Set strict: false in production to prevent throwing errors for undefined roles or resources. This prevents service disruptions if a role is referenced that doesn't exist.

const rbac = new RBACManager(config, {
  strict: process.env.NODE_ENV === 'development'
});

3. Enable Caching

Always use caching in production for better performance:

const rbac = new RBACManager(config, {
  cache: {
    enabled: true,
    maxSize: 1000, // Limit cache size to prevent memory issues
    ttl: 5 * 60 * 1000 // Cache TTL of 5 minutes
  }
});

4. Properly Set Up Role Hierarchy

Remember that in the hierarchy object:

  • The key is the child role (the one inheriting permissions)
  • The array values are parent roles (the ones being inherited from)
// CORRECT:
rbac.setRoleHierarchy({
  'EDITOR': ['ADMIN'], // EDITOR inherits from ADMIN
});

// INCORRECT (would mean ADMIN inherits from EDITOR):
rbac.setRoleHierarchy({
  'ADMIN': ['EDITOR']
});

5. Use Custom Logger

Configure a custom logger to integrate with your application's logging system:

const rbac = new RBACManager(config, {
  logger: {
    debug: (msg) => myLogger.debug(`[RBAC] ${msg}`),
    info: (msg) => myLogger.info(`[RBAC] ${msg}`),
    warn: (msg) => myLogger.warn(`[RBAC] ${msg}`),
    error: (msg) => myLogger.error(`[RBAC] ${msg}`)
  }
});

6. Implement Resource Ownership

For multi-tenant systems, combine RBAC with resource ownership checks:

// Middleware to check both permissions and ownership
const checkPermissionAndOwnership = (req, res, next) => {
  const resourceId = req.params.id;
  const userId = req.user.id;
  
  // First check RBAC permissions
  if (!rbac.userCan(req.user, 'Orders', 'UPDATE')) {
    return res.status(403).json({ error: 'Permission denied' });
  }
  
  // Then check ownership
  orderService.getOrderById(resourceId)
    .then(order => {
      if (order.userId !== userId) {
        return res.status(403).json({ error: 'Not your order' });
      }
      next();
    });
};

Security Features

This package includes security-focused features to protect your application's permission system:

  1. Input Validation: All role, resource, and permission inputs are validated to prevent injection attacks and manipulation.

  2. Circular Reference Detection: Automatic detection and prevention of circular references in role hierarchies.

  3. Default Deny: The system always defaults to denying access when errors occur or when roles/permissions are undefined.

  4. Deep Cloning: All configuration objects are deep-cloned to prevent external mutation attacks.

  5. Protected Cache Keys: The caching system uses sanitized keys to prevent cache poisoning.

  6. Secure Middleware: The Express middleware is designed to securely handle errors and always default to access denial.

  7. Audit Logging: Built-in audit logging for critical permission changes and access attempts.

  8. Type Safety: TypeScript types enforce proper structure and prevent common mistakes.

  9. Race Condition Protection: Special handling to prevent race conditions during permission updates.

  10. Secure Error Handling: Error messages are designed to avoid leaking sensitive information.

Advanced Examples

For more advanced usage examples, check the examples directory in the repository:

  • product-shop.ts: Basic e-commerce example with standard roles
  • express-integration.ts: Example integration with Express.js middleware
  • advanced-example.ts: Complex role hierarchy with comprehensive permissions

API Reference

RBACManager

The main class for managing RBAC functionality.

// Create a new instance
const rbac = new RBACManager(config, options);

// Check if a role has permission
rbac.can(role, resource, permission);

// Check if a user has permission
rbac.userCan(user, resource, permission);

// Set role hierarchy
rbac.setRoleHierarchy(hierarchy);

// Update configuration
rbac.updateConfig(config);

// Add a new role
rbac.addRole(role, definition);

// Remove a role
rbac.removeRole(role);

// Grant permissions
rbac.grant(role, resource, permission);

// Revoke permissions
rbac.revoke(role, resource, permission);

// Evaluate a policy
rbac.evaluatePolicy(policy);

// Get permissions for a role on a resource
rbac.getPermissions(role, resource);

// Get all resources a role has access to
rbac.getResources(role);

// Get all roles
rbac.getRoles();

// Get the complete configuration
rbac.getConfig();

// Clear the permission cache
rbac.clearCache();

// Get cache statistics
rbac.getCacheStats();

// Create middleware
rbac.middleware(options);

RBACBuilder

A fluent API for building RBAC configurations.

// Create a new builder
const builder = new RBACBuilder();

// Define roles and permissions
builder
  .role('ADMIN')
    .grantFullAccess('Products')
    .done()
  .role('EDITOR')
    .forResource('Products').grant('READ', 'UPDATE').and()
    .forResource('News').grantAll().done()
  .setDefaultRole('EDITOR');

// Build the configuration
const config = builder.build();

Build and Development

Building the Project

This project provides both development and production build options:

# Development build (with source maps and comments)
npm run build

# Production build (minified with source maps)
npm run build:prod

Minification

The production build automatically minifies the JavaScript output using Terser with the following optimizations:

  • Code compression (removing whitespace, shortening variable names)
  • Dead code elimination
  • Mangling of variable names for smaller file size
  • Preservation of license/copyright comments
  • Sourcemap generation for debugging

This results in significantly smaller file sizes while maintaining full functionality.

License

MIT

版本与发布记录

@anishpras/rbac 共发布 7 个版本,首次发布于 2025/03/28;过去 12 个月发布了 0 个版本。

版本发布日期距今
2.1.1latest2025/03/281.6 年前
2.1.02025/03/281.6 年前
2.0.12025/03/281.6 年前
2.0.02025/03/281.6 年前
1.1.02025/03/281.6 年前
1.0.12025/03/281.6 年前

关于 @anishpras/rbac 的常见问题

@anishpras/rbac 是什么?

A fast, flexible, and production-ready role-based access control (RBAC) system for JavaScript/TypeScript applications.

如何安装 @anishpras/rbac?

在项目目录运行 npm install @anishpras/rbac,或使用 pnpm add / yarn add / bun add。

@anishpras/rbac 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@anishpras/rbac 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@anishpras/rbac 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=14.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@anishpras/rbac 可以商用吗?

@anishpras/rbac 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@anishpras/rbac 的下载量有多少?

根据 npm 官方下载统计,@anishpras/rbac 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,949 次,日均约 98 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@anishpras/rbac 还在维护吗?

最新版本 2.1.1 发布于 2025/03/28(1.6 年前);至今共发布 7 个版本,其中过去 12 个月发布了 0 个;首次发布于 2025/03/28。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。