spekkionu / laravel-zend-acl
Adds ACL to Laravel via Laminas\Permissions\Acl component.
Installs: 72 067
Dependents: 0
Suggesters: 0
Security: 0
Stars: 41
Watchers: 5
Forks: 9
Open Issues: 1
Requires
- php: >=8.0
- illuminate/support: 6.* | 7.* | 8.* | 9.* | 10.*
- laminas/laminas-permissions-acl: ^2.14
Requires (Dev)
- mockery/mockery: ~1.0
- phpunit/phpunit: ^8.0
README
Adds ACL to Laravel 5 or Lumen via Laminas\Permissions\Acl component.
Most of the ACL solutions for Laravel store the permissions rules in the database or other persistance layer. This is great if access is dynamic but for applications with set permissions by roles this makes modification more difficult. Adding new resources, permissions, or roles requires runnning db queries via a migration or other means. With this package the permissions are stored in code and thus in version control (hopefully).
Rather than reinvent the wheel this package makes use of the Acl package from Zend Framework. Documentation for the Laminas\Permissions\Acl can be found at https://docs.laminas.dev/laminas-permissions-acl/
Installation
Run composer require spekkionu/laravel-zend-acl
from your project root.
Setup
Laravel
- For Laravel versions less than 5.5 Add
'Spekkionu\ZendAcl\ZendAclServiceProvider',
to the service provider list inconfig/app.php
. This step is not necessary for Laravel 5.5+. - Add
'Acl' => 'Spekkionu\ZendAcl\Facades\Acl',
to the list of aliases inconfig/app.php
. - Run
php artisan vendor:publish --provider="Spekkionu\ZendAcl\ZendAclServiceProvider"
After publishing the permissions will be defined in routes/acl.php
.
Lumen
- Add
$app->register(Spekkionu\ZendAcl\ZendAclLumenServiceProvider::class);
to theRegister Service Providers
section inbootstrap/app.php
. - Copy the
vendor/spekkionu/laravel-zend-acl/src/config/zendacl.php
file to theconfig
folder in the app root (create the folder if it does not exist). - Copy the
vendor/spekkionu/laravel-zend-acl/src/config/acl.php
file to theroutes
folder (this folder should also contain theweb.php
routes file).
Migrating from version 6
The namespace for the Zend framework libraries has changed from Zend to Laminas.
To migrate to the 7.x branch you will need to change any references to the old Zend namespace in your project to the new Laminas namespace.
This will likely include changing the RoleInterface your user model implements from Zend\Permissions\Acl\Role\RoleInterface
to Laminas\Permissions\Acl\Role\RoleInterface
.
Also anywhere you are type hinting for Zend\Permissions\Acl\Acl
to Laminas\Permissions\Acl\Acl
.
Usage
The Laminas\Permissions\Acl is available through the Facade Acl or through the acl service in the IOC container. The IOC container can also inject the acl instance by type-hinting Laminas\Permissions\Acl\Acl.
The permissions can be modified at app/Http/acl.php
.
Adding a Resource
You can add a new resource using the addResource method.
<?php // Add using string shortcut $acl->addResource('page'); // Add using instance of the Resource class $acl->addResource(new \Laminas\Permissions\Acl\Resource\GenericResource('someResource')); ?>
Adding a Role
You can add a new resource using the addRole method.
<?php // Add using string shortcut $acl->addRole('admin'); // Add using instance of the Role class $acl->addRole(new \Laminas\Permissions\Acl\Role\GenericRole('member')); ?>
Adding / Removing Permissions
You can add permissions using the allow method.
<?php // Add page resource $acl->addResource('page'); // Add admin role $acl->addRole('admin'); // Add guest role $acl->addRole('guest'); // Give admin role add, edit, delete, and view permissions for page resource $acl->allow('admin', 'page', array('add', 'edit', 'delete', 'view')); // Give guest role only view permissions for page resource $acl->allow('guest', 'page', 'view'); ?>
You can remove permissions using the deny method.
<?php // Add page resource $acl->addResource('page'); // Add admin role $acl->addRole('admin'); // Give admin role add, edit, delete, and view permissions for page resource $acl->allow('admin', 'page', array('add', 'edit', 'delete', 'view')); // Add staff role that inheirits from admin $acl->addRole('staff', 'admin'); // Deny access for staff role the delete permission on the page resource $acl->deny('staff', 'page', 'delete'); ?>
Checking for permissions
You can check for access using the isAllowed method
Given the following permissions:
<?php // Add page resource Acl::addResource('page'); // Add admin role Acl::addRole('admin'); // Add guest role Acl::addRole('guest'); // Give admin role add, edit, delete, and view permissions for page resource Acl::allow('admin', 'page', array('add', 'edit', 'delete', 'view')); // Give guest role only view permissions for page resource Acl::allow('guest', 'page', 'view'); ?>
<?php // Check if admin can add page // Should return true $allowed = Acl::isAllowed('admin', 'page', 'add'); // Check if admin can delete page // Should return true $allowed = Acl::isAllowed('admin', 'page', 'delete'); // Check if guest can edit page // Should return false $allowed = Acl::isAllowed('guest', 'page', 'edit'); // Check if guest can view page // Should return true $allowed = Acl::isAllowed('guest', 'page', 'view'); ?>
Checking permissions for a user
In order to check permissions for a logged in user the user needs to have a field that stores the user's role. If using an Eloquent user model have the user model implement Laminas\Permissions\Acl\Role\RoleInterface. This interface has one method getRoleId() that should return the role for the user.
Example Model
Say there is a table users
that has a field role
The following model will allow an instance of the User model to be passed to the isAllowed() method.
<?php use Illuminate\Database\Eloquent\Model; use Laminas\Permissions\Acl\Role\RoleInterface; class User extends Model implements RoleInterface { /** * The database table used by the model. * * @var string */ protected $table = 'users'; /** * Returns role of the user * @return string */ public function getRoleId() { return $this->role; } }
Using the user model to check permissions
<?php // Checking if a user has permissions to view an article $user = User::find(1); Acl::isAllowed($user, 'article', 'view'); // Checking if the currently logged in user has permissions to edit a blog post Acl::isAllowed(Auth::user(), 'post', 'edit');
Adding permission checks to routes
There is an acl route middleware included in this package that lets you restrict access by route.
The route middleware requires the model returned by Auth::user() to implement Laminas\Permissions\Acl\Role\RoleInterface
as above.
Registering the acl middleware
Laravel
Add the following to the $routeMiddleware
array in app/Http/Kernel.php
'acl' => \Spekkionu\ZendAcl\AclMiddleware::class,
Lumen
Add the following to the array in the $app->routeMiddleware()
method in bootstrap/app.php
'acl' => \Spekkionu\ZendAcl\AclMiddleware::class,
Using the acl middleware
You can add the middleware to any route as a before middleware such as the following.
Route::get('article/{id}', ['middleware' => ['acl:article,view'], 'uses' => 'ArticleController@show']);
When the route is requested it will check if the currently logged in user has is allowed the view privilege on the article resource.
If there is no logged in user (Auth::guest() returns true) the role guest
will be checked.
If the user has access to the given resource then the controller will be called as normal.
What happens of the user is not allowed access to the resource is configurable in config/zendacl.php
.
There are two different actions that can be taken if the user is not authorized.
-
The user can be redirected to a url or named route. This can be set by setting the
action
setting to "redirect" or "route" and theredirect
setting to the url or named route. -
A view can be rendered. This can be set by setting the
action
to "view". Theview
setting controls the view to be rendered. By default the view will be located atresources/vendor/zendacl/unauthorized
. This view can be modified or theview
setting can be changed to another view.
Ajax requests will be sent a 401 response regardless of the settings.