zennit / abac
Attribute-Based Access Control (ABAC) for Laravel
Requires
- php: ^8.2
- laravel/framework: ^11.2
- laravel/sanctum: ^4.0
Requires (Dev)
- laravel/pint: ^1.18
- mockery/mockery: ^1.6
- orchestra/testbench: ^9.8
- phpbench/phpbench: ^1.3
- phpunit/phpunit: ^11.5
- dev-main
- 6.6.0
- 6.5.6
- 6.5.5
- 6.5.4
- 6.5.3
- 6.5.2
- 6.5.1
- 6.5.0
- 6.4.7
- 6.4.6
- 6.4.5
- 6.4.4
- 6.4.3
- 6.4.2
- 6.4.1
- 6.4.0
- 6.3.6
- 6.3.5
- 6.3.4
- 6.3.3
- 6.3.2
- 6.3.1
- 6.3.0
- 6.2.1
- 6.2.0
- 6.1.0
- 6.0.10
- 6.0.9
- 6.0.8
- 6.0.7
- 6.0.6
- 6.0.5
- 6.0.4
- 6.0.3
- 6.0.2
- 6.0.1
- 6.0.0
- 5.1.1
- 5.1.0
- 5.0.4
- 5.0.3
- 5.0.2
- 5.0.1
- 5.0.0
- 4.5.4
- 4.5.3
- 4.5.2
- 4.5.1
- 4.5.0
- 4.4.0
- 4.3.3
- 4.3.2
- 4.3.1
- 4.3.0
- 4.2.1
- 4.2.0
- 4.1.2
- 4.1.1
- 4.1.0
- 4.0.10
- 4.0.9
- 4.0.8
- 4.0.7
- 4.0.6
- 4.0.5
- 4.0.4
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- 3.0.2
- 3.0.1
- 3.0.0
- 2.9.0
- 2.8.1
- 2.8.0
- 2.7.6
- 2.7.4
- 2.7.2
- 2.7.0
- 2.6.1
- 2.6.0
- 2.5.1
- 2.5.0
- 2.4.1
- 2.4.0
- 2.3.0
- 2.2.0
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.10
- 1.0.9
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.0
- dev-fix-migrations-and-update
- dev-tests
This package is auto-updated.
Last update: 2025-04-19 10:14:52 UTC
README
A flexible and powerful ABAC implementation for Laravel applications.
Table of Contents
- Introduction
- Prerequisites
- Installation
- Quick Start
- Basic Usage
- API Routes
- Commands
- Configuration
- Database Schema
- Performance Monitoring
- License
- Contributing
- Reporting Issues & Questions
Introduction
ABAC provides fine-grained access control by evaluating attributes of users, resources, and the context of a request.
This package integrates seamlessly with Laravel to offer powerful access control mechanisms.
Prerequisites
- Laravel 11.0 or higher
- LaravelSanctum 4.0 or higher
- PHP 8.2 or higher
Installation
Install the package via Composer:
composer require zennit/abac
Add the service provider to your bootstrap/providers.php
:
return [ # ... other providers zennit\ABAC\Providers\AbacServiceProvider::class, ];
Quick Start
Migrate
php artisan migrate
Setup initial data using the provided JSON files. You can use the following example JSON structure to seed your database
{ "object_attributes": [ { "object_id": 1, "attribute_name": "posts_id", "attribute_value": "1" }, { "object_id": 2, "attribute_name": "user_id", "attribute_value": "1" } ], "subject_attributes": [ { "subject": "App\\Models\\User", "subject_id": 1, "attribute_name": "role", "attribute_value": "editor" } ], "policies": [ { "resource": "App\\Models\\Post", "method": "view", "chains": [ { "operator": "or", "chains": [ { "operator": "or", "checks": [ { "operator": "equals", "context_accessor": "object.posts.id", "value": "1" }, { "operator": "equals", "context_accessor": "object.user.id", "value": "1" } ] } ] }, { "operator": "or", "checks": [ { "operator": "equals", "context_accessor": "object.posts.id", "value": "1" }, { "operator": "equals", "context_accessor": "object.user.id", "value": "1" } ] } ] } ] }
This example creates a policy that determines who can view posts. It allows viewing when either:
- The post ID equals 1, OR
- The user ID equals 1
This JSON structure follows the database schema:
object_attributes
: Maps toabac_object_additional_attributes
tablesubject_attributes
: Maps toabac_subject_additional_attributes
tablepolicies
: Maps toabac_policies
tablechains
: Maps toabac_chains
table (supports nested chains viachain_id
)checks
: Maps toabac_checks
table
Note: The chains
array supports nested structures where a chain can reference another chain using the chain_id
field. Either chain_id
or checks
must be provided in a chain, but not both.
Before running the seeder
- Make sure you have published the configuration file and set the correct paths for the JSON files in your environment.
php artisan abac:publish
This will add the required environment variables to your .env
file and create the configuration file at
config/abac.php
.
- Also include the DatabaseSeeder into your
DatabaseSeeder
class
use zennit\ABAC\Database\Seeders\DatabaseSeeder as ABACDatabaseSeeder; class DatabaseSeeder extends Seeder { public function run() { // Other seeders... $this->call(ABACDatabaseSeeder::class, []); } }
Run the seeder command
php artisan db:seed --class=AbacSeeder
After seeding the database
The final step to complete the setup is to add the trait to all the classes you have defined in path_patterns in the configuration file.
- Check the Configuration section for more details.
Basic Usage
Here's an example of how to perform access control checks:
use zennit\ABAC\DTO\AccessContext; use zennit\ABAC\Facades\Abac; # Using the Facade $context = new AccessContext( method: $method, subject: (new AbacAttributeLoader())->loadAllSubjectAttributes(get_class('App\Models\User')), object: (new AbacAttributeLoader())->loadAllSubjectAttributes(get_class('App\Models\Post')), object_type: get_class('App\Models\User'), subject_type: get_class('App\Models\Post'), ); # AbacCheck returns boolean $hasAccess = Abac::can($context); # Using the helper functions $hasAccess = abacPolicy()->can($context); # Cache management helper abacCache()->warm('posts'); # Warm cache for posts abacCache()->invalidate(); # Invalidate all cache abacCache()->clear(); # Clear all cache
The can()
method evaluates the access request and returns a boolean indicating whether access is granted.
The evaluate()
method can be used to get detailed information about the evaluation process, look
at AccessResult for more details.
The evaluation result is automatically cached using the subject ID, resource, and operation as the cache key.
Available Operators
All operators are defined in the src/Enums/Operators
directory
Logical Operators
and
or
Arithmetic Operators
equals
not_equals
greater_than
less_than
greater_than_equals
less_than_equals
String Operators
contains
not_contains
starts_with
ends_with
not_starts_with
not_ends_with
Note: Make sure when creating new objects in the database, you make use of these operators, not doing so is going to make the conditions invalid. If you want us to support other operators make a PR or raise an issue
Middleware
The ABAC package uses the EnsureAccess Middleware to check whether the requesting user has the necessary permissions to access a specific resource and method.
How It Works
The middleware is automatically registered when you add the service provider to your bootstrap/providers.php
file. It
evaluates access requests based on the following parameters:
- Resource: The resource being accessed (e.g.,
App\Models\Post
,App\Models\User
, etc.). - Method: The HTTP method of the request (e.g.,
GET
,POST
, etc.). - Subject: The user making the request (e.g.,
$request->user()
).
For more details, refer to the AccessContext class.
Accessing the Evaluation Result
After processing the request, the middleware adds the evaluation result to the request object. You can access it using
$request->abac()
.
Usage Example
To use the middleware, simply apply it to your routes. For example:
Route::apiResource('users', UserController::class)->middleware('abac');
Important Notes
- Ensure that the
abac
middleware is applied to the routes you want to protect. - The middleware evaluates access dynamically based on the defined policies and attributes.
API Routes
The following API routes are available for managing ABAC-related data. These routes must be protected by the abac
middleware (look at Configuration for more details) and can be prefixed using the ABAC_ROUTE_PREFIX
environment variable:
For Update and Create Operations
When creating or updating ABAC resources, you have flexibility in how you structure your requests, as long as they comply with the validation rules defined in the FormRequests classes. These rules ensure data integrity and proper relationships between policies, chains, and checks.
You can create complex policy structures in a single request or build them incrementally through separate API calls. The validation system will ensure that your data maintains proper hierarchical relationships and contains all required fields.
For detailed validation rules and request structure examples, refer to the FormRequest classes:
- AbacPolicyRequest
- AbacChainRequest
- AbacCheckRequest
- AbacObjectAttributeRequest
- AbacSubjectAttributeRequest
Pagination
All index responses are paginated and support the following query parameters:
page
: The page number to retrieve (default: 1)per_page
: The number of items per page (default: 10)
The pagination response format includes both the data items and pagination metadata:
{ "items": [], "pagination": { "firstPage": 1, "currentPage": 1, "lastPage": 10, "firstPageUrl": "localhost:8000/{prefix}/object-attributes?page=1", "lastPageUrl": "localhost:8000/{prefix}/object-attributes?page=10", "perPage": 10, "nextPageUrl": "localhost:8000/{prefix}/object-attributes?page=2", "prevPageUrl": null, "total": 100, "hasMorePages": true } }
Object Attributes
-
Get Object Attributes
- Endpoint:
/{prefix}/object-attributes
- Method:
GET
- Description: Retrieve a list of object attributes.
- Request Body: None
- Response:
{ "object_id": 1, "attribute_name": "name_1", "attribute_value": "val_1" }
- Endpoint:
-
Delete Object Attribute
- Endpoint:
/{prefix}/object-attributes/{id}
- Method:
DELETE
- Description: Delete a specific object attribute by ID.
- Request Body: None
- Response:
{ "message": "Object Attribute deleted successfully." }
- Endpoint:
Subject Attributes
-
Get Subject Attributes
- Endpoint:
/{prefix}/subject-attributes
- Method:
GET
- Description: Retrieve a list of subject attributes.
- Request Body: None
- Endpoint:
-
Response:
{ "subject": "App\\Models\\User", "subject_id": 1, "attribute_name": "role", "attribute_value": "admin" }
-
Delete Subject Attribute
- Endpoint:
/{prefix}/subject-attributes/{id}
- Method:
DELETE
- Description: Delete a specific subject attribute by ID.
- Request Body: None
- Response:
{ "message": "Subject attribute deleted successfully." }
- Endpoint:
Policies
-
Get Policies
- Endpoint:
/{prefix}/policies
- Method:
GET
- Description: Retrieve a list of policies.
- Request Body: None
- Response:
{ "id": 1, "resource": "posts", "method": "view", "chains": [] }
- Endpoint:
-
Delete Policy
- Endpoint:
/{prefix}/policies/{id}
- Method:
DELETE
- Description: Delete a specific policy by ID.
- Request Body: None
- Response:
{ "message": "Policy deleted successfully." }
- Endpoint:
Chains
-
Get Chains
- Endpoint:
/{prefix}/policies/{policy}/chains
- Method:
GET
- Description: Retrieve a list of chains for a given policy.
- Request Body: None
- Response:
{ "id": 1, "operator": "and", "checks": [] }
- Endpoint:
-
Delete Chain
- Endpoint:
/{prefix}/policies/{policy}/chains/{id}
- Method:
DELETE
- Description: Delete a specific chain from a policy.
- Request Body: None
- Response:
{ "message": "Chain deleted successfully." }
- Endpoint:
Checks
-
Get Checks
- Endpoint:
/{prefix}/policies/{policy}/chains/{chain}/checks
- Method:
GET
- Description: Retrieve a list of checks for a given chain.
- Request Body: None
- Response:
{ "id": 1, "operator": "greater_than", "context_accessor": "object.view_count", "value": "1000" }
- Endpoint:
-
Delete Check
- Endpoint:
/{prefix}/policies/{policy}/chains/{chain}/checks/{id}
- Method:
DELETE
- Description: Delete a specific check from a chain.
- Request Body: None
- Response:
{ "message": "Check deleted successfully." }
- Endpoint:
To register the ABAC routes in your application, create a new service provider:
php artisan make:provider AbacServiceProvider
Then update the provider to register the routes:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use zennit\ABAC\Facades\Abac; class AbacRoutesServiceProvider extends ServiceProvider { public function boot() { // Register ABAC routes with custom middleware Abac::routes([ 'middleware' => ['api', 'auth'], // Add your middleware here 'prefix' => 'abac' // Optional: customize the route prefix ]); // Load ABAC macros so you have access to $request->abac() Abac::macros(); } }
Register your new service provider in config/app.php
:
'providers' => [ // ... App\Providers\AbacRoutesServiceProvider::class, ],
Commands
Publishing Commands
# Publish all ABAC files (config and env variables) php artisan abac:publish # Individual publishing commands php artisan abac:publish-config # Publish configuration file only php artisan abac:publish-env # Publish environment variables only
Force Options
All commands support the --force
option to skip confirmations:
php artisan abac:publish --force php artisan abac:publish-config --force php artisan abac:publish-env --force
Cache Management
# Warm the entire policy cache php artisan abac:cache-warm # Warm cache for specific resource php artisan abac:cache-warm posts # Invalidate cache php artisan abac:cache-invalidate # Clear cache php artisan abac:cache-clear
Configuration
Environment Variables
ABAC_CACHE_ENABLED=true # Enable/disable the caching system ABAC_CACHE_STORE=database # Cache store to use (database, redis, file, etc.) ABAC_CACHE_TTL=3600 # Cache time-to-live in seconds ABAC_CACHE_PREFIX=abac_ # Prefix for cache keys ABAC_CACHE_WARMING_ENABLED=true # Enable/disable automatic cache warming ABAC_CACHE_WARMING_SCHEDULE=hourly # Schedule for cache warming (hourly, daily, etc.) ABAC_STRICT_VALIDATION=true # Enable strict validation of attributes and policies ABAC_LOGGING_ENABLED=true # Enable/disable logging ABAC_LOG_CHANNEL=abac # Logging channel for ABAC events ABAC_DETAILED_LOGGING=false # Enable detailed logging of evaluations ABAC_PERFORMANCE_LOGGING_ENABLED=true # Enable performance metric logging ABAC_SLOW_EVALUATION_THRESHOLD=100 # Threshold (ms) for slow evaluation warnings ABAC_EVENTS_ENABLED=true # Enable/disable event dispatching ABAC_OBJECT_ADDITIONAL_ATTRIBUTES=App\Models\User # Model class for object attributes ABAC_MIDDLEWARE_OBJECT_METHOD=user # Method to retrieve object in middleware
Full Configuration Options
<?php return [ 'cache' => [ 'enabled' => env('ABAC_CACHE_ENABLED', true), 'store' => env('ABAC_CACHE_STORE', 'database'), 'ttl' => env('ABAC_CACHE_TTL', 3600), 'prefix' => env('ABAC_CACHE_PREFIX', 'abac_'), ], 'monitoring' => [ 'logging' => [ 'enabled' => env('ABAC_LOGGING_ENABLED', true), 'channel' => env('ABAC_LOG_CHANNEL', 'abac'), 'detailed' => env('ABAC_DETAILED_LOGGING', false), ], 'performance' => [ 'enabled' => env('ABAC_PERFORMANCE_LOGGING_ENABLED', true), 'slow_threshold' => env('ABAC_SLOW_EVALUATION_THRESHOLD', 100), ], ], 'database' => [ 'object_additional_attributes' => env('ABAC_OBJECT_ADDITIONAL_ATTRIBUTES', 'App\Models\User'), 'soft_deletes_column' => 'deleted_at', ], 'seeders' => [ 'object_attribute_path' => 'stubs/abac/object_attribute_path.json', 'subject_attribute_path' => 'stubs/abac/subject_attribute_path.json', 'policy_file_path' => 'stubs/abac/abac_policy_file_path.json', ], 'middleware' => [ 'object_method' => env('ABAC_MIDDLEWARE_OBJECT_METHOD', 'user'), 'excluded_routes' => [ // Simple wildcard pattern - excludes all methods 'current-user*', // Matches current-user, current-user/profile, etc. 'stats*', // Matches stats, stats/daily, etc. // Exclude specific methods for a route pattern [ 'path' => 'posts*', // Wildcard support 'method' => ['GET', 'POST', 'PUT'] // Array of methods to exclude ], // Exclude all methods for a specific path [ 'path' => 'blogs*', 'method' => '*' ], // Exclude single method [ 'path' => 'comments*', 'method' => 'GET' ] ], // key value pairs for matching the URI to its associated method, required for the middleware to work 'path_patterns' => [ 'users/(/[^/]+)?' => 'App\Models\User', 'users/(/[^/]+)/posts/(/[^/]+)?' => 'App\Models\Post', ] ], ];
Database Schema
Performance Monitoring
The ABAC package includes built-in performance monitoring capabilities:
Caching System
- Automatic Result Caching: Access control evaluations are automatically cached to improve performance
- Configurable Cache Store: Supports multiple cache backends (database, Redis, file, etc.) via the
ABAC_CACHE_STORE
setting - Custom Cache Prefix: All cache keys use the configured prefix (
ABAC_CACHE_PREFIX
) for easy identification - Cache Registry: The system maintains a registry of all cache keys for efficient invalidation
- Serialization Strategy: Evaluation results are serialized efficiently, storing SQL queries and bindings rather than full objects
Cache Management
- All evaluation results are cached by default to improve performance
- Cache storage uses the store defined in your configuration (
ABAC_CACHE_STORE
) - Cache warm-up can be scheduled with
ABAC_CACHE_WARMING_SCHEDULE
option - If caching is disabled (
ABAC_CACHE_ENABLED=false
), evaluations will be performed for each request
Performance Metrics
- The package monitors the performance of all access control evaluations
- Any evaluation that takes longer than the configured threshold (
ABAC_SLOW_EVALUATION_THRESHOLD
, default 100ms) will log a warning - Performance metrics can be viewed in your configured log channel (
ABAC_LOG_CHANNEL
)
These monitoring tools help identify and resolve performance bottlenecks in your access control policies.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
Contributions are welcome! Please read the CONTRIBUTING file for details on how to contribute to this project.
Reporting Issues & Questions
If you encounter any issues, have questions, or need assistance with the ABAC package, please feel free to open an issue on our GitHub repository:
https://github.com/zennit-dev/abac/issues
Our team monitors the issues board regularly and will respond as soon as possible. When reporting issues, please include:
- Laravel and PHP versions
- Package version
- Steps to reproduce the issue
- Expected and actual behavior
- Any relevant error messages or logs
This helps us address your concerns more efficiently.