aurorawebsoftware / aauth
Laravel Aauth
Installs: 1 684
Dependents: 1
Suggesters: 0
Security: 0
Stars: 40
Watchers: 2
Forks: 7
Open Issues: 9
Requires
- php: ^8.2|^8.3|^8.4
- laravel/framework: ^11.0|^12.0
- laravel/pint: ^1.13
- spatie/laravel-package-tools: ^1.16.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.35
- larastan/larastan: ^3.0
- nunomaduro/collision: ^8.1
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^11.0
- spatie/laravel-ray: ^1.33
- dev-main
- 12.0.6
- 12.0.5
- 12.0.4
- 12.0.3
- 12.0.2
- 12.0.1
- 12.0.0
- 11.0.0
- 1.4.0
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.1
- 1.1.0
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- 0.0.3
- 0.0.2
- 0.0.1
- dev-docs-abac-enhancements
- dev-feature/devcontainer
- dev-dependabot/github_actions/dependabot/fetch-metadata-2.4.0
- dev-remove-unnecessary-files
- dev-phpstan-fixes-v2
- dev-some-migration-fix
- dev-version-fix
- dev-can-function-fix
- dev-organization-node-model-update
- dev-migration-fix
- dev-laravel-12-update
- dev-update
- dev-performans_improvoment
- dev-node_error_path
- dev-refactor-query-builder-for-updated-abac-rules
- dev-polymorphic-update-organization-node
- dev-model-id-fix
- dev-organization_node_ids_function
- dev-updates
- dev-abac
- dev-new_static_methods_added_to_AAuthOrganizationNodeInterface
This package is auto-updated.
Last update: 2025-05-27 09:55:16 UTC
README
Organization Based (OrBAC) , Attibute Based (ABAC) , Rol-Permission (RBAC) Based Authentication Methods Combined Laravel Auth Package with Limitless Hierarchical Level of Organizations and Limitless Attribute Conditions
Features
- Organization Based Access Controllable (OrBAC) Eloquent Models
- Attribute Based Access Controllable (ABAC) Eloquent Models
- Role Based Access Control (RoBAC)
- Permissions Based Access Control
- Lean & Non-Complex Architecture
- PolyMorphic Relationships of Model & Organization Node
- DB Row Level Filtering for the Role with ABAC
- Built-in Blade Directives for permission control inside Blade files
- Mysql, MariaDB, Postgres Support
- Community Driven and Open Source Forever
Installation
You can install the package via composer:
composer require aurorawebsoftware/aauth
You must add AAuthUser Trait to the User Model and User Model must implement AAuthUserContract
use Illuminate\Foundation\Auth\User as Authenticatable; use AuroraWebSoftware\AAuth\Traits\AAuthUser; use AuroraWebSoftware\AAuth\Contracts\AAuthUserContract; class User extends Authenticatable implements AAuthUserContract { use AAuthUser; // ... }
You can publish and run the migrations with:
php artisan migrate
You can publish the sample data seeder with:
php artisan vendor:publish --tag="aauth-seeders"
php artisan db:seed --class=SampleDataSeeder
Optionally, You can seed the sample data with:
php artisan db:seed --class=SampleDataSeeder
You can publish the config file with:
php artisan vendor:publish --tag="aauth-config"
This is the example contents of the published config file:
return [ 'permissions' => [ 'system' => [ 'edit_something_for_system' => 'aauth/system.edit_something_for_system', 'create_something_for_system' => 'aauth/system.create_something_for_system', ], 'organization' => [ 'edit_something_for_organization' => 'aauth/organization.edit_something_for_organization', 'create_something_for_organization' => 'aauth/organization.create_something_for_organization', ], ], ];
Main Philosophy of AAuth OrBAC
In computer system security, there are several approaches to restrict system access to authorized users.
Most used and known access control method is Rol Based Access Control (RoBAC).
In most circumstances, it's sufficient for software projects. Basically; Roles and Permissions are assigned to the Users, The data can be accessed horizontally as single level
What if your data access needs are further more than one level? and what if you need to restrict and filter the data in organizational and hierarchical manner?
Let's assume we need to implement a multi-zone, multi-level school system and be our structure like this.
- Türkiye
- A High School
- Class 1A
- Class 2A
- B High School
- Class 1A
- A High School
- Germany
- X High School
- Class 1B
- Class 2B
- X High School
How can you restrict A High School's data from X High School Principal and Teachers?
How can you give permissions to a Class Teacher to see their students only ?
What if we need another level of organization in the future like this? and want to give access to see students data under their responsibility only for Europe Zone Principal, Türkiye Principal dynamically without writing one line of code?
- Europe
- Türkiye
- A High School
- Class 1A
- Class 2A
- B High School
- Class 1A
- A High School
- Germany
- X High School
- Class 1B
- Class 2B
- X High School
- Türkiye
- America
- USA
- ....
- ....
- Canada
- .....
- USA
Main Philosophy of AAuth ABAC
In the context of the AAuth package, Attribute-Based Access Control (ABAC) is an advanced system for creating dynamic, attribute-based filtering scopes for your Eloquent models. It allows you to define granular access rules that operate directly on the attributes of the models themselves. When a user attempts to retrieve data, these rules are automatically applied to the database queries, ensuring that only records matching the specified attribute conditions for the user's current role are returned.
Core Concepts in AAuth's ABAC:
- Model Attributes: These are the characteristics of your Eloquent model instances, directly corresponding to the columns in your database tables (e.g., an
Order
model might have attributes likestatus
,amount
,created_at
,customer_id
). AAuth's ABAC rules are built around evaluating these attributes. - Rules/Policies: In AAuth, ABAC rules are structured statements that define conditions based on model attributes. For example, a rule might state "only allow access to
Order
models where thestatus
attribute is 'completed' AND theamount
attribute is greater than 100." These rules are stored and associated with user roles (see "Managing ABAC Rules and Associations") but the conditions within the rules operate on the attributes of the Eloquent model being queried. The syntax for these rules is detailed in "Defining ABAC Rules".- While traditional ABAC systems might also heavily feature subject attributes (e.g., user's department, security clearance) and environment conditions (e.g., time of day) as direct inputs into the rule structure, AAuth's primary focus for its ABAC rule definitions is on the attributes of the data/model itself. External factors like user properties or current time can be incorporated by dynamically constructing the rule's values before they are stored or used, but the rule engine itself primarily processes conditions against model attributes.
Benefits of ABAC in AAuth:
Framed by AAuth's model-centric approach, the benefits include:
- Fine-Grained Data Filtering: ABAC enables highly specific filtering of Eloquent model records, moving beyond broad role-based permissions to control access down to individual records based on their attributes.
- Dynamic Query Modification: Access to data can change dynamically as the attributes of the model records change, without needing to redefine roles or permissions. For instance, if an
Invoice
model'spayment_status
attribute changes to 'paid', an ABAC rule can automatically restrict access for roles that should only see unpaid invoices. - Reduced Complexity in Roles: Instead of creating numerous specific roles for slightly different data access needs, ABAC allows for fewer roles, with the data visibility for those roles being dynamically shaped by attribute-based rules.
- Centralized Access Logic for Data Records: Rules pertaining to data attributes are defined and managed in a structured way, making it easier to understand and audit who can access what data.
ABAC in AAuth: How It Works
AAuth implements its ABAC capabilities by allowing you to:
- Define rules based on the attributes of your Eloquent models (e.g., for an
Order
model, rules might useOrder->status
orOrder->amount
). - Associate these rules with specific user roles.
- Automatically apply these rules as database query conditions whenever data is fetched for an ABAC-enabled model.
For example, a rule might specify that users with a "Support Tier 1" role can only access Ticket
models where the Ticket->priority
is 'low' and Ticket->is_open
is true. If a Ticket
's priority
changes, or it's closed, it automatically falls out of scope for that user role. This powerful filtering is applied seamlessly, as detailed in the "Automatic Query Filtering (ABAC)" section.
This model-attribute-focused ABAC complements the Organization-Based Access Control (OrBAC) and Role-Based Access Control (RBAC) features of AAuth, allowing for a robust, multi-layered access control strategy.
AAuth may be your first class assistant package.
If you don't need organizational roles, AAuth may not be suitable for your work.
AAuth Terminology
Before using AAuth its worth to understand the main terminology of AAuth. AAuth differs from other Auth Packages due to its organizational structure.
What is Organization?
Organization is a kind of term which refers to hierarchical arrangement of eloquent models in sequential tree.
It consists of a central root organization node, and sub organization nodes, which are connected via edges. We can also say that organization tree has one root node, many sub organization nodes polymorphic-connected with one eloquent model.
Organization Scope
In Organization Tree, each node has an organization scope. Organization scope has a level property to determine the level of the organization node in the tree.
Organization Node
Each node in the organization tree means organization node. Each Organization Node is an Eloquent Model. Organization Node can be polymorphic-related with an Eloquent Model.
Permission
In This Package there are 2 types of Permissions.
- System Permissions
- Organization Permissions
System Permission is plain permission non-related to the organization which is useful for system related access
controls like backup_db, edit_website_logo, edit_contact_info etc..
A System permission can only be assigned to a System Role. System Permissions should be added inside aauth.php
config
file's permission['system'] array.
Organization Permission is hierarchical controllable permission. An Organization permission can only be assigned to
an Organization Role.
Organization Permissions should be added inside aauth.php
config file's permission['organization'] array.
ABAC
Attribute-Based Access Control. AAuth provides comprehensive ABAC features, allowing for fine-grained access control based on model attributes. For a detailed explanation, see the sections:
- "Main Philosophy of AAuth ABAC"
- "Using ABAC Interface and Trait with Eloquent Models"
- "Defining ABAC Rules"
- "Managing ABAC Rules and Associations"
- "Automatic Query Filtering (ABAC)"
Role
Roles are assigned to users. Each User can have multiple roles.
In This Package there are 2 types of Roles.
- System Roles
- Organization Roles
System Role is plain role for non-related to the organization which is useful for system related users like system admin, super admin etc..
Organization Role is hierarchical position of a User in Organization Tree. An Organization Role can be assigned to a user with 3 parameters.
- user_id (related user's id)
- role_id
- organization_node_id (id of the organization node which defines the position of the user's role on the organization Tree)
! it can be a little overwhelming at the first, but it is not complex lol. :)
User
Just a usual Laravel User. AAuthUser trait must be added to Default User Model.
Permission Config File
Permissions are stored inside config/aauth.php
which is published after installing.
Model - Organization Node Relations
Each Organization Node can have a polymorphic relationship with an Eloquent Model. By doing this, an Eloquent Model can be an organization node and can be access controllable.
It means that; Only Authorized User Role can be access the relating model, or in other words, Each role only can access the models which is on Authenticated Sub-Organization Tree of User's Role.
Defining ABAC Rules
Attribute-Based Access Control (ABAC) rules in AAuth determine whether a user has access to a specific Eloquent model instance based on its attributes. These rules are defined as a PHP array, which can also be represented as a JSON string that decodes into the equivalent array structure. This allows for dynamic rule creation and storage.
The rules are typically defined within your ABAC-enabled Eloquent model by implementing the getABACRules(): array
method from the AAuthABACModelInterface
. These rules are then automatically applied by the AAuthABACModelScope
when querying the model.
Overall Structure:
An ABAC rule set is fundamentally a nested array structure that always starts with a top-level logical operator, either &&
(AND) or ||
(OR). This operator dictates how the conditions or condition groups directly under it are evaluated.
- If the top-level operator is
&&
, all direct child conditions/groups must evaluate to true. - If the top-level operator is
||
, at least one direct child condition/group must evaluate to true.
Each element within the top-level operator's array is either a single condition or another nested group of conditions (which itself starts with a logical operator).
Example of basic structure:
[ // Top-level logical operator '&&' => [ // Condition 1 ['=' => ['attribute' => 'status', 'value' => 'active']], // Condition 2 ['>' => ['attribute' => 'amount', 'value' => 100]], // Nested group of conditions ['||' => [ ['=' => ['attribute' => 'category', 'value' => 'electronics']], ['=' => ['attribute' => 'category', 'value' => 'books']] ]] ] ]
In this example:
Access is granted if (status
is 'active' AND amount
is greater than 100) AND (category
is 'electronics' OR category
is 'books').
Logical Operators:
Logical operators define how multiple conditions are combined.
-
&&
(AND): All conditions or nested groups within this block must be true for this part of the rule to be satisfied.[ '&&' => [ // Condition A // Condition B ] ] // Both Condition A AND Condition B must be true.
-
||
(OR): At least one of the conditions or nested groups within this block must be true for this part of the rule to be satisfied.[ '||' => [ // Condition X // Condition Y ] ] // Either Condition X OR Condition Y (or both) must be true.
Nesting Logical Operators: You can nest these operators to create complex logic:
[ '&&' => [ // Outer AND ['=' => ['attribute' => 'is_published', 'value' => true]], // Condition 1 ['||' => [ // Inner OR ['=' => ['attribute' => 'visibility', 'value' => 'public']], // Condition 2a ['=' => ['attribute' => 'owner_id', 'value' => '$USER_ID']] // Condition 2b (assuming $USER_ID is a placeholder you'd replace) ]] ] ] // Access if: is_published is true AND (visibility is 'public' OR owner_id matches the user's ID)
Conditional Operators:
Conditional operators are used to compare a model's attribute with a specific value. The AAuthABACModelScope
leverages Laravel's underlying database query builder, so standard SQL comparison operators are generally available. Common ones include:
=
: Equal to.!=
or<>
: Not equal to.>
: Greater than.<
: Less than.>=
: Greater than or equal to.<=
: Less than or equal to.LIKE
: Simple string matching (e.g.,value
can be'%' . $searchTerm . '%'
).NOT LIKE
: Negated string matching.IN
: Value is within a given array. Thevalue
for anIN
condition should be an array.NOT IN
: Value is not within a given array. Thevalue
for aNOT IN
condition should be an array.
Condition Structure:
Each individual condition is an array where the key is the conditional operator, and the value is another array containing attribute
and value
keys.
[ // Conditional Operator (e.g., '=') '=' => [ 'attribute' => 'model_column_name', // The column name on your Eloquent model 'value' => 'the_value_to_compare_against' ] ]
attribute
: A string representing the name of the attribute (database column) on the Eloquent model being queried.value
: The value to compare the attribute against. This can be a string, number, boolean, or an array (especially forIN
andNOT IN
operators).
Practical Examples:
-
Allow if
status
is 'active':[ '&&' => [ ['=' => ['attribute' => 'status', 'value' => 'active']] ] ]
(Note: Even for a single condition, it must be wrapped in a top-level logical operator.)
-
Allow if
order_value
is greater than or equal to 1000:[ '&&' => [ ['>=' => ['attribute' => 'order_value', 'value' => 1000]] ] ]
-
Allow if
is_urgent
is true ANDpriority
is greater than 5:[ '&&' => [ ['=' => ['attribute' => 'is_urgent', 'value' => true]], ['>' => ['attribute' => 'priority', 'value' => 5]] ] ]
-
Allow if
department
is 'sales' ORdepartment
is 'support': This can be written in two ways: Using||
:[ '||' => [ ['=' => ['attribute' => 'department', 'value' => 'sales']], ['=' => ['attribute' => 'department', 'value' => 'support']] ] ]
Using
IN
:[ '&&' => [ // Top level can be && if this is the only group ['IN' => ['attribute' => 'department', 'value' => ['sales', 'support']]] ] ]
-
Complex: Allow if (
type
is 'document' ANDfile_format
is 'pdf') OR (type
is 'image' ANDresolution
is 'high'):[ '||' => [ // Top-level OR [ // First group: document conditions '&&' => [ ['=' => ['attribute' => 'type', 'value' => 'document']], ['=' => ['attribute' => 'file_format', 'value' => 'pdf']] ] ], [ // Second group: image conditions '&&' => [ ['=' => ['attribute' => 'type', 'value' => 'image']], ['=' => ['attribute' => 'resolution', 'value' => 'high']] ] ] ] ]
-
Example adapted from
README-abac.md
(made concrete): Original abstract idea:// { // "&&": [ // { "==": [ "$attribute", "asd" ] }, // { "==": [ "$attribute", "asd" ] }, // { "||": [ // { "==": [ "$attribute", "asd" ] }, // { "==": [ "$attribute", "asd" ] } // ] // } // ] // }
Concrete AAuth PHP array:
[ '&&' => [ ['=' => ['attribute' => 'product_category', 'value' => 'electronics']], ['=' => ['attribute' => 'brand', 'value' => 'AwesomeBrand']], [ '||' => [ ['=' => ['attribute' => 'region', 'value' => 'EU']], ['=' => ['attribute' => 'region', 'value' => 'US']] ] ] ] ] // Access if: category is 'electronics' AND brand is 'AwesomeBrand' AND (region is 'EU' OR region is 'US')
By defining these rules in the getABACRules()
method of your ABAC-enabled models, AAuth will automatically filter database queries to ensure users can only access records that meet the specified attribute conditions for their role.
Usage
Before using this, please make sure that you published the config files.
AAuth Services, Service Provider and roleId
Session and Facade
AAuth Services are initialized inside AAuthService Provider.
roleId session must be set before initializing AAuth Service.
AAuthServiceProvider.php
$this->app->singleton('aauth', function ($app) { return new AAuth( Auth::user(), Session::get('roleId') ); });
there is also a AAuth Facade to access AAuth Service class statically. Example;
AAuth::can();
OrganizationService
Organization Service is used for organization related jobs. The service can be initialized as
$organizationService = new OrganizationService()
or via dependency injecting
public function index(OrganizationService $organizationService) { ..... }
Creating an Organization Scope
$data = [ 'name' => 'Org Scope1', 'level' => 5, 'status' => 'active', ]; $organizationService->createOrganizationScope($data);
Updating an Organization Scope
// todo help wanted
Deleting an Organization Scope
// todo help wanted
Creating an Organization Node without Model Relationship
$orgScope = OrganizationScope::first(); $data = [ 'name' => 'Created Org Node 1', 'organization_scope_id' => $orgScope->id, 'parent_id' => 1, ]; $organizationService->createOrganizationNode($data);
Updating an Organization Node
// todo help wanted
Deleting an Organization Node
// todo help wanted
Role Permission Service
This Service is used for role related jobs. The service can be initialized as
$rolePermissionService = new RolePermissionService()
or via dependency injecting
public function index(RolePermissionService $rolePermissionService) { ..... }
Creating a Role
$organizationScope = OrganizationScope::whereName('Root Scope')->first(); $data = [ 'organization_scope_id' => $organizationScope->id, 'type' => 'system', 'name' => 'Created System Role 1', 'status' => 'active', ]; $createdRole = $rolePermissionService->createRole($data);
Updating a Role
// todo help wanted
Deleting a Role
// todo help wanted
Attaching a Role to a User
$role = Role::whereName('System Role 1')->first(); $permissionName = 'test_permission1'; $rolePermissionService->attachPermissionToRole($permissionName, $role->id);
Syncing All Permissions for a Role
$role = Role::whereName('System Role 1')->first(); $permissionName1 = 'test_permission1'; $permissionName2 = 'test_permission2'; $permissionName3 = 'test_permission3'; $rolePermissionService->syncPermissionsOfRole( compact('permissionName1', 'permissionName2', 'permissionName3'), $role->id );
Detaching Permission from a Role
$rolePermissionService->detachSystemRoleFromUser($role->id, $user->id);
Creating an Organization Role and Attaching to a User
$organizationScope = OrganizationScope::whereName('Root Scope')->first(); $organizationNode = OrganizationNode::whereName('Root Node')->first(); $data = [ 'organization_scope_id' => $organizationScope->id, 'type' => 'organization', 'name' => 'Created Organization Role 1 for Attaching', 'status' => 'active', ]; $createdRole = $rolePermissionService->createRole($data); $rolePermissionService->attachOrganizationRoleToUser($organizationNode->id, $createdRole->id, $user->id);
Creating a System Role and Attaching to a User
// todo help wanted
Using AAuth Interface and Trait with Eloquent Models
To turn an Eloquent Model into an AAuth Organization Node; Model must implement AAuthOrganizationNodeInterface
and use AAuthOrganizationNode
Trait.
After adding AAuthOrganizationNode
trait, you will be able to use AAuth methods within the model
namespace App\Models\ExampleModel; use AuroraWebSoftware\AAuth\Interfaces\AAuthOrganizationNodeInterface; use AuroraWebSoftware\AAuth\Traits\AAuthOrganizationNode; use Illuminate\Database\Eloquent\Model; class ExampleModel extends Model implements AAuthOrganizationNodeInterface { use AAuthOrganizationNode; // implementation }
Using ABAC Interface and Trait with Eloquent Models
To make your Eloquent models controllable via Attribute-Based Access Control (ABAC) with AAuth, you need to implement an interface and use a specific trait. This allows AAuth to understand how to apply attribute-based rules to your models.
Requirements:
- Your Eloquent model must implement the
AuroraWebSoftware\AAuth\Contracts\AAuthABACModelInterface
. - Your Eloquent model must use the
AuroraWebSoftware\AAuth\Traits\AAuthABACModel
trait.
Implementation Example:
Here's an example of how to set up an Eloquent model (e.g., Order
) for ABAC:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use AuroraWebSoftware\AAuth\Contracts\AAuthABACModelInterface; use AuroraWebSoftware\AAuth\Traits\AAuthABACModel; class Order extends Model implements AAuthABACModelInterface { use AAuthABACModel; // Your model's other properties and methods... /** * Get the type of the model for ABAC. * This is typically a string that identifies your model. * * @return string */ public static function getModelType(): string { return 'order'; // Or any unique string identifier for this model type } /** * Define the ABAC rules for this model. * These rules determine how access is granted based on attributes. * The detailed structure and syntax for these rules are covered in the "Defining ABAC Rules" section. * This method can serve as a fallback or default if no specific rule is found for the current user's role * via the `RoleModelAbacRule` model, or it can be the primary source if role-specific ABAC rules are not used. * * @return array */ public static function getABACRules(): array { // Example: Return an empty array as a placeholder, or define default/fallback rules here. // For instance, to allow access if 'status' is 'active' by default: // return [ // '&&' => [ // ['=' => ['attribute' => 'status', 'value' => 'active']] // ] // ]; // If no role-specific rule is found via RoleModelAbacRule, these rules (if any) might be applied. // If you exclusively use RoleModelAbacRule for all ABAC logic, this method can safely return an empty array. return []; } }
This setup prepares your model to have ABAC rules applied to it. The getModelType()
method provides a string identifier for your model type, which can be used in rule definitions. The getABACRules()
method is where you can define default or fallback attribute conditions for accessing instances of this model. While the primary mechanism for applying role-specific rules is via the RoleModelAbacRule
model (see "Managing ABAC Rules and Associations"), these model-defined rules can act as a base or default. The detailed format for the rule syntax is covered in the "Defining ABAC Rules" section.
AAuth Service and Facade Methods
// todo
Current Roles All Permissions
current user's selected roles permissions with AAuth Facade
$permissions = AAuth::permissions();
Check allowed permission with can() method
AAuth::can('create_something_for_organization');
if (AAuth::can('create_something_for_organization')) { // codes here }
Check permission and abort if not user and current allowed
AAuth::passOrAbort('create_something_for_organization');
Get all permitted organization nodes
it will return OrganizationNode collection.
organizationNodes(bool $includeRootNode = false, ?string $modelType = null): \Illuminate\Support\Collection
$organizationNodes = AAuth::organizationNodes();
Get one specified organization node
// todo help wanted
Descendant nodes can be checked
with this method you can check is a organization node is descendant of another organization node. in other words, checks if node is sub-node of specified node.
$isDescendant = AAuth::descendant(1, 3);
Creating an Organization Node-able Model and Related Org. Node
with this method, you can create a model and organization node with relationship together.
$data = ['name' => 'Test Organization Node-able Example']; $createdModel = ExampleModel::createWithAAuthOrganizationNode($data, 1, 2);
Getting Related Organization Node of Model
$exampleModel = ExampleModel::find(1); $relatedOrganizationModel = $exampleModel->relatedAAuthOrganizationNode()
Getting authorized Models only. (OrBAC)
after adding AAuthOrganizationNode
trait to your model, you are adding a global scope which filters the permitted data.
Thus, you can simply use any eloquent model method without adding anything
ExampleModel::all();
Managing ABAC Rules and Associations
While the "Defining ABAC Rules" section explains the structure of ABAC rules, this section details how those rules are associated with specific roles and managed within the AAuth system. AAuth uses a dedicated Eloquent model to store these associations, allowing for dynamic and granular control over which rules apply to which roles for different types of models.
1. Association with Roles: The RoleModelAbacRule
Model
ABAC rules are not globally applied or solely defined in the model's getABACRules()
method (though that method can serve as a default or fallback). Instead, for role-specific ABAC, rules are linked to roles via the AuroraWebSoftware\AAuth\Models\RoleModelAbacRule
Eloquent model.
This model has the following key fields:
role_id
: The ID of theRole
to which this specific ABAC rule applies.model_type
: A string that identifies the ABAC-enabled Eloquent model. This string must match the value returned by the staticgetModelType()
method on your ABAC-enabled model (e.g.,'order'
,'post'
,'product'
). This ensures the rules are applied to the correct model.rules_json
: A JSON field where the actual ABAC rule array (as documented in "Defining ABAC Rules") is stored. When creating or updating, you can typically provide a PHP array, and Eloquent will handle the JSON conversion if the model's casts are set up appropriately (which is common for JSON fields).
2. Creating and Assigning Rules
To apply a specific set of ABAC rules to a role for a particular model, you create an instance of RoleModelAbacRule
.
Example:
Let's say you have an Order
model that is ABAC-enabled (implements AAuthABACModelInterface
and uses AAuthABACModel
trait, with Order::getModelType()
returning 'order'
). You want to create a rule for a specific role (e.g., "Regional Manager") that only allows them to see 'approved' orders with an amount greater than or equal to 100.
use AuroraWebSoftware\AAuth\Models\Role; use AuroraWebSoftware\AAuth\Models\RoleModelAbacRule; use App\Models\Order; // Your ABAC-enabled Order model // Assume $regionalManagerRole is an existing Role instance $regionalManagerRole = Role::where('name', 'Regional Manager')->first(); if ($regionalManagerRole) { // Define the ABAC rules for the 'Order' model specifically for this role $orderRulesForRole = [ '&&' => [ ['=' => ['attribute' => 'status', 'value' => 'approved']], ['>=' => ['attribute' => 'amount', 'value' => 100]] ] ]; // Create or update the rule for this role and model type RoleModelAbacRule::updateOrCreate( [ 'role_id' => $regionalManagerRole->id, 'model_type' => Order::getModelType(), // This will return 'order' ], [ 'rules_json' => $orderRulesForRole // Provide the array directly ] ); echo "ABAC rules for Orders assigned to Regional Manager role.\n"; }
In this example, updateOrCreate
is used to either create a new rule association or update an existing one if a rule for that specific role_id
and model_type
already exists.
3. Viewing, Modifying, and Deleting Rules
Since RoleModelAbacRule
is a standard Eloquent model, you can manage these rule associations using familiar Eloquent methods:
-
Viewing:
// Get all rules for a specific role $rulesForRole = RoleModelAbacRule::where('role_id', $role->id)->get(); // Get the rule for a specific role and model $specificRule = RoleModelAbacRule::where('role_id', $role->id) ->where('model_type', Order::getModelType()) ->first(); if ($specificRule) { $rulesArray = $specificRule->rules_json; // Accesses the casted array }
-
Modifying:
$ruleToUpdate = RoleModelAbacRule::find(1); // Or fetch by role_id and model_type if ($ruleToUpdate) { $newRules = [ /* ... new rule definition ... */ ]; $ruleToUpdate->update(['rules_json' => $newRules]); }
-
Deleting:
$ruleToDelete = RoleModelAbacRule::find(1); if ($ruleToDelete) { $ruleToDelete->delete(); } // Or delete by role and model type RoleModelAbacRule::where('role_id', $role->id) ->where('model_type', Order::getModelType()) ->delete();
4. Facade Method for Rule Retrieval: AAuth::ABACRules()
AAuth provides a facade method to retrieve the applicable ABAC rules for the currently authenticated user's active role and a specific model type:
AAuth::ABACRules(string $modelType): ?array
$modelType
: The string identifier for the model (e.g.,'order'
, as returned byYourModel::getModelType()
).
This method is primarily used internally by the AAuthABACModelScope
. When you query an ABAC-enabled model (e.g., Order::all()
), the scope automatically calls AAuth::ABACRules(Order::getModelType())
.
Here's how it works:
- AAuth identifies the current user (typically via
Auth::user()
). - It determines the user's currently active role. This is usually set via
Session::get('roleId')
when the AAuth service is initialized (see "AAuth Services, Service Provider androleId
Session and Facade"). - It then queries the
role_model_abac_rules
table for an entry matching the activerole_id
and the provided$modelType
. - If a matching rule is found, it returns the
rules_json
content as a PHP array. - If no specific rule is found for that role and model type, it may return
null
(or potentially fall back to default rules defined in the model'sgetABACRules()
method, depending on the full implementation logic ofAAuthABACModelScope
andAAuth::ABACRules()
).
This mechanism ensures that the ABAC rules applied are specific to the user's current operational role, providing a powerful and flexible way to manage data access.
Automatic Query Filtering (ABAC)
A key strength of AAuth's Attribute-Based Access Control (ABAC) implementation is its ability to automatically filter Eloquent queries. This ensures that users only retrieve model records that they are authorized to access based on the ABAC rules defined for their current role, without needing to manually add conditions to every query.
1. Introduction to Global Scope: AAuthABACModelScope
When you use the AuroraWebSoftware\AAuth\Traits\AAuthABACModel
trait in your Eloquent model, AAuth automatically registers a global Eloquent scope called AuroraWebSoftware\AAuth\Scopes\AAuthABACModelScope
. This scope is responsible for intercepting database queries for that model and applying the necessary ABAC rule conditions.
2. Automatic Filtering in Action
Once your model is correctly set up with the AAuthABACModel
trait, and you have defined ABAC rules and associated them with a user's current role via the RoleModelAbacRule
model (as described in "Managing ABAC Rules and Associations"), the filtering is seamless:
- Any standard Eloquent query you execute, such as
YourModel::all()
,YourModel::where('some_column', 'some_value')->get()
,YourModel::find($id)
, or even queries through relationships, will automatically have the ABAC rules applied. - The
AAuthABACModelScope
fetches the relevant ABAC rules for the active user's role and the model being queried (usingAAuth::ABACRules(YourModel::getModelType())
). - These rules are then translated into
WHERE
clauses that are added to your database query. - Consequently, the query results will only include records that satisfy the conditions defined in the applicable ABAC rules. If no rules are defined for the role, or if the rules permit all access, then all records will be returned (subject to other query conditions).
3. Example Scenario
Let's illustrate with an Order
model that is ABAC-enabled:
- The
App\Models\Order
model uses theAAuthABACModel
trait. - The user's currently active role has an ABAC rule associated with the
'order'
model type (Order::getModelType() returns 'order'). This rule is:// Rule stored in RoleModelAbacRule for the user's role and 'order' model_type: // [ // '&&' => [ // ['=' => ['attribute' => 'status', 'value' => 'completed']] // ] // ]
- The
orders
table in your database contains orders with various statuses: 'pending', 'processing', 'completed', 'cancelled'.
Now, when the user performs queries:
use App\Models\Order; // Fetch all orders // Despite no explicit where('status', 'completed') here, // AAuth will automatically add this condition based on the user's role's ABAC rules. // $completedOrders will only contain orders where status is 'completed'. $completedOrders = Order::all(); foreach ($completedOrders as $order) { // echo $order->status; // Will always output 'completed' } // Fetch a specific order by ID $order1 = Order::find(1); // If Order ID 1 has status 'pending', $order1 will be null. $order2 = Order::find(2); // If Order ID 2 has status 'completed', $order2 will be the Order model. // Even more complex queries are filtered: $highValueCompletedOrders = Order::where('amount', '>', 500)->get(); // This will return orders where amount > 500 AND status is 'completed'.
This automatic filtering significantly enhances security and simplifies development, as the access control logic is centralized and consistently applied without requiring developers to remember to add specific WHERE
clauses for authorization in every query.
4. Bypassing the ABAC Scope
There might be rare situations (e.g., in administrative tools or specific internal processes) where you need to retrieve all records without ABAC filtering. You can bypass the global AAuthABACModelScope
just like any other global Eloquent scope:
use AuroraWebSoftware\AAuth\Scopes\AAuthABACModelScope; use App\Models\Order; // Retrieve all orders, ignoring ABAC rules for this specific query $allOrdersIncludingNonCompleted = Order::withoutGlobalScope(AAuthABACModelScope::class)->get(); // Find a specific order by ID, ignoring ABAC rules $anyOrder = Order::withoutGlobalScope(AAuthABACModelScope::class)->find(1);
The withoutGlobalScopes()->all()
method mentioned earlier in the "Getting All Model Collection without any access control" section also effectively bypasses this and all other global scopes. Use this capability judiciously, as it circumvents the defined access controls.
Getting All Model Collection without any access control
ExampleModel::withoutGlobalScopes()->all()
that's all.
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
// todo ? Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.
Development Environment using Dev Containers
This project includes a Dev Container configuration, which allows you to use a Docker container as a fully-featured development environment.
Prerequisites
- Docker Desktop installed and running.
- Visual Studio Code installed.
- Dev Containers extension for VS Code installed.
Getting Started
- Clone this repository to your local machine.
- Open the cloned repository in Visual Studio Code.
- When prompted with "Reopen in Container", click the button. (If you don't see the prompt, open the Command Palette (
Ctrl+Shift+P
orCmd+Shift+P
) and run "Dev Containers: Reopen in Container".)
This will build the dev container and install all necessary dependencies. You can then develop and run the application from within this isolated environment.