rab-access
Version:
Role based access control
227 lines (180 loc) • 6.89 kB
Markdown
# **Rab Access Control Middleware**
A robust, flexible, and declarative access control library for Node.js applications. With `rab-access`, you can define and enforce fine-grained access policies using schemas, roles, and custom validations. It’s ideal for multi-role systems requiring granular control over resource access.
---
## **Features**
- **Declarative Schema-Based Access Control**: Define access policies for resources and operations.
- **Role-Based Permissions**: Grant permissions based on roles and extend roles with additional access rights.
- **Dynamic Filters and Validators**: Use dynamic data (e.g., user attributes, query parameters) to filter or validate access.
- **Middleware Generation**: Seamlessly integrate with your Node.js apps via middleware.
---
## **Installation**
Install the package using npm:
```bash
npm install rab-access
```
---
## **Getting Started**
### **1. Import Required Modules**
```javascript
const { Rab } = require("rab-access");
```
### **2. Define Roles**
Define the roles within your system:
```javascript
const roles = {
SYSTEM_ADMIN: "System Admin",
ADMIN: "Admin",
SUPERVISOR: "Supivisor",
};
```
### **3. Define Access Control Schema**
Create a schema that specifies access rules for various operations:
```javascript
const userAccessControl = Rab.schema({
canReadUser: [
Rab.alwaysGrant().ifEqual(Rab.user("user_id"), Rab.params("user_id")),
Rab.grant(roles.SYSTEM_ADMIN).columns(["id"]),
Rab.grant(roles.ADMIN).filters({
"organization_id": Rab.user( "organization_id")
})
.columns(["id"]),
Rab.grant(roles.SUPERVISOR)
.extend(roles.ADMIN, "canReadUser")
.columns(["id", "name"]),
],
canReadAllUsers: [Rab.grant(roles.SYSTEM_ADMIN).columns(["id"])],
canDeleteUser: [
Rab.alwaysGrant().ifEqual(Rab.user("user_id"), Rab.params("user_id")),
Rab.grant(roles.SYSTEM_ADMIN),
Rab.grant(roles.SUPERVISOR).validator("customValidationFunction"),
],
});
```
### **4. Define Custom Validations**
Add custom validation logic for specific scenarios:
```javascript
const customValidations = {
customValidationFunction: async (request) => {
// Perform your custom validation
return Promise.resolve();
},
};
```
### **5. Generate Middleware**
Create middleware to enforce your access policies:
```javascript
const createMiddleware =
(accessControl, validations) => (permission) => async (req, res, next) => {
const { isAuthorized, fields, filters, lookupFilters } =
await accessControl.can({
validations,
request: req,
role: req.role,
permission,
});
if (isAuthorized) {
req.fields = fields;
req.filters = filters;
req.lookupFilters = lookupFilters;
return next();
}
res.status(403).json({ error: "FORBIDDEN" });
};
const accessMiddleware = createMiddleware(userAccessControl, customValidations);
```
### **6. Export and Use**
Export the middleware and roles for use in your application:
```javascript
module.exports = {
accessMiddleware,
roles,
};
```
---
## **Usage Example**
Integrate the middleware into your application to secure routes:
```javascript
const express = require("express");
const { accessMiddleware, roles } = require("./accessControl");
const app = express();
// Example route using middleware
app.get("/users/:userId", accessMiddleware("canReadUser"), (req, res) => {
res.send("Access granted to a user data!");
});
app.get("/users", accessMiddleware("canReadAllUsers"), (req, res) => {
res.send("Access granted to a users!");
});
app.listen(3000, () => console.log("Server running on port 3000"));
```
## **API Reference**
### **Core Classes**
#### **`Rab`**
The main class for managing access control. Use it to define schemas, manage roles, and evaluate permissions.
##### **Methods**
- **`Rab.schema(config: Record<string, Permission[]>)`**
Defines the access control schema with a configuration object mapping actions to role-based permissions.
- **Parameters**:
- `config`: An object where keys are permission names and values are arrays of `Permission` instances.
- **Example**:
```javascript
Rab.schema({
canReadUsers: [
Rab.grant("Admin").columns(["id", "name"]),
],
});
```
- **`Rab.grant(role: string): Permission`**
Creates a new `Permission` instance for a specific role.
- **`Rab.user(path: string[] | string): string[]`**
Retrieves the user's data path for dynamic access control rules.
- **`Rab.params(path: string[] | string): string[]`**
Retrieves the request parameters path for dynamic access control.
- **`Rab.query(path: string[] | string): string[]`**
Retrieves the query parameters path for dynamic access control.
- **`Rab.can(options: Omit<EvaluatePermissionParams, "permissions"> & { permission: string }): Promise<Authorization>`**
Checks if a user is authorized to perform a specific action.
- **Parameters**:
- `options`: Includes the role, request, and permission name.
- **Returns**: A promise resolving to an `Authorization` object.
- **Example**:
```javascript
const {isAuthorized} = await Rab.can({
role: "Admin",
request: req,
permission: "canReadUsers",
});
```
---
#### **`Permission`**
Defines the rules and constraints for a specific role's access.
##### **Methods**
- **`columns(columns: string[]): this`**
Specifies the columns that the role can access.
- **`lookupFilters(filters: Record<string, any>): this`**
Adds lookup filters to the permission.
- **`filters(filters: Record<string, any>): this`**
Adds filters to refine the permission further.
- **`ifEqual(...fields: string[][]): this`**
Adds an equality condition for the permission.
- **Parameters**:
- `fields`: Arrays of field pairs to compare for equality.
- **`ifContains(...fields: string[][]): this`**
Adds a containment condition for the permission.
- **Parameters**:
- `fields`: Arrays of field pairs to check for containment.
- **`validator(method: string, variables?: Record<string, any>): this`**
Adds a custom validator function to the permission.
- **Parameters**:
- `method`: The name of the custom validation method.
- `variables`: Optional key-value map of variables.
- **`extend(role: string, permission: string): this`**
Extends another permission for the current role.
- **Parameters**:
- `role`: The base role.
- `permission`: The name of the permission to extend.
## **Contributing**
Contributions are welcome! Feel free to submit issues or pull requests to improve this library.
---
## **License**
This project is licensed under the [MIT License](LICENSE).
---