tanerkay/laravel-model-acl

Access control based on individual records / models

v0.3-beta 2023-07-02 08:09 UTC

This package is auto-updated.

Last update: 2024-05-31 00:23:20 UTC


README

This package allows record-level access control based on custom authorization rules.

This handles cases where you may have many records in a table, but each entity has its own rules for access control. For example, you may have a table of documents, and it's not a simple scenario where a user can edit their own documents, and view all others. Maybe the access of each document has to be set separately, e.g. document X can be edited by Bob & Jane, and viewed by the Staff group; whereas document Y can only be viewed by the Finance team.

Here's a demo of how you can use it:

use Illuminate\Database\Eloquent\Model;
use Tanerkay\ModelAcl\Traits\ModelBasedAccessControl;

class Report extends Model
{
    use ModelBasedAccessControl;
    
    // ...
}

$post->can('view');

Support the developer

To be added...

Documentation

Installation

Requires PHP 8.0 or higher, and Laravel 8.x or higher (currently supporting up to 9.x)

composer require tanerkay/laravel-model-acl

You can publish the migration with:

php artisan vendor:publish --provider="Tanerkay\ModelAcl\ModelAclServiceProvider" --tag="model-acl-migrations"
php artisan migrate

You can optionally publish the config file with:

php artisan vendor:publish --provider="Tanerkay\ModelAcl\ModelAclServiceProvider" --tag="model-acl-config"

Assigning access control rules to individual models

The addAccessControl() method can be used to add rules to individual models.

public function addAccessControl(
    string|array $abilities, 
    object|array $ruleDefinitions, 
    ?string $description = null
): void

It accepts:

  • an ability name or list of abilities that can be used in calls to can().
  • an array of rule definitions, each rule definition is an array containing a class string 'class' and an array of arguments 'arguments'.
  • an optional description of the rule, which can be stored in the database alongside the rule definition.

e.g. Restrict a certain post to moderators and admins.

$post->addAccessControl('view', [
    [
        'class' => \Tanerkay\ModelAcl\Rules\HasRole::class,
        'arguments' => ['admin', 'moderator'],
    ]
]);

// throws exception if $user->hasRole(['admin', 'moderator']) doesn't return true
$post->can('view');

The HasRole class assumes your User model has a method hasRole() that accepts a string or an array of strings. You can customize the name of the method using the env key MODEL_ACL_AUTHENTICATABLE_HAS_ROLE.

Creating custom rules

For other rules or logic, you can construct your own Rule class which implements \Tanerkay\ModelAcl\Contracts\RuleContract or which extends the abstract class \Tanerkay\ModelAcl\Rules\Rule.

e.g.

use Tanerkay\ModelAcl\Rules\Rule;

class AgeRequirementRule extends Rule
{
    public function authorize(?Authenticatable $user, ...$arguments): void
    {
        $user ??= $this->getUser();

        if ($user->date_of_birth->diffInYears() < $arguments[0]) {
            throw new \Exception('Not wise enough');
        }
    }
}
$drink = Drink::where('is_alcoholic', true)->first();

$drink->addAccessControl('buy', [
    [
        'class' => AgeRequirementRule::class,
        'arguments' => 18,
    ]
]);

// throws exception if user is under 18 years of age
$drink->can('buy');

Testing

composer test

Thanks

  • Spatie for making awesome packages, this package leverages spatie/laravel-package-tools and is itself derived from spatie/laravel-activitylog.

License

The MIT License (MIT)