coucounco / laravel-acl
Access Control List for Laravel
Installs: 1 382
Dependents: 0
Suggesters: 0
Security: 0
Stars: 4
Watchers: 2
Forks: 1
Open Issues: 2
Requires
- php: >=8.1.0
- illuminate/auth: ^10.0
- illuminate/container: ^10.0
- illuminate/contracts: ^10.0
- illuminate/database: ^10.0
Requires (Dev)
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^9
This package is auto-updated.
Last update: 2024-10-09 09:51:28 UTC
README
This is a package that provide Access Control List for Laravel 6.0|7.0|8.0|9.0.
For Laravel 6.0|7.0|8.0 use v1.
For Laravel 9.0 use v2.
Getting started
This package can be installed through Composer:
composer require coucounco/laravel-acl
After installation you must perform these steps:
1) Add the service provider in config/app.php
file:
'providers' => [
// ...
coucounco\LaravelAcl\ServiceProvider::class,
];
2) Publish the laravel-acl config in your app
This step will copy config files in the config folder of your Laravel App.
config/acl.php
congig/acl/users.php
php artisan vendor:publish --provider="coucounco\LaravelAcl\ServiceProvider"
When it is published you can manage the configuration of larvel-acl through the file in config/acl.php
, it contains:
<?php
return [
/*
* Defaults for laravel-acl
*/
'defaults' => [
/**
* The acls consists in a set of permissions for a given entity.
* Here you can set the default acls (acls defined in the models section of this config file) used by laravel-acl
*/
'acls' => 'users',
],
/**
* Here you map models to acls.
*
* You can add new row by adding :
* [Model] => [acls_name]
*
* After adding a new line here, you will need to add a new configuration files under config/acl/[acls_name].php
*/
'models' => [
App\Models\User::class => 'users',
],
/**
* Cache configuration
*/
'cache' => [
'enable' => true,
'key' => 'laravel-acl_',
'store' => '',
'expiration_time' => 432000
],
];
3) Configure acls
laravel-acl
provide acls and permissions not only to one model (default App\Models\User
) but you can configure many. By default, the acls users
that is using the model App\Models\User
is used.
But you can add more acls if needed.
'defaults' => [
'acls' => 'users',
],
'models' => [
App\Models\User::class => 'users',
],
Exemple :
'defaults' => [
'acls' => 'users',
],
'models' => [
App\Models\User::class => 'users',
App\Models\Member::class => 'members',
],
Each acls have a config file associated. users
has config/acl/users.php
and contains the following :
<?php
return [
/**
* Register every permissions here
* key is the name of the permission
* value is the id of the permission
* Every permissions can have a different access level
* 0 = ACL_NONE -> no permission
* 1 = ACL_READ -> read permission
* 2 = ACL_CREATE -> create permission
* 3 = ACL_UPDATE -> update permission
* 4 = ACL_DELETE -> delete permission
* Access level are incrmental. If user has a permission with an access level of ACL_CREATE
* it means that the user can ACL_READ and ACL_CREATE
*/
'permissions' => [
'superadmin' => 0,
'user' => 1,
'group' => 2,
'page' => 3,
],
/**
*
*/
'roles' => [
'admins' => "1",
'user' => "0",
],
'model' => [
// direct acl on user
'user' => [
/**
* Enable acl for user
*/
'enableAcl' => true,
/**
* The attribute where the acl is stored in the User model.
* It's basically the name of the column in the database
*/
'attributeName' => 'acl',
],
// acl via groups of user
// n-n relation between user and group
'group' => [
/**
* Enable acl for group
*/
'enableAcl' => false,
/**
* The name of the relationship from the User model to the "group" model
*/
'relationship' => 'groups',
/**
* The attribute where the acl is stored in the "group" model.
* It's basically the name of the column in the database
*/
'attributeName' => 'acl',
]
],
'cache' => [
'key' => 'laravel-acl_',
'store' => '',
'expiration_time' => 432000
]
];
3) Configure ACL for users
Optionally, you can enable direct acl on User
To enable this feature, you have to edit model.user.enableAcl
it in the config/acl/users.php
file and do the following instructions.
If you don't want direct acl on user, you can jump to the next chapter.
3.1) Update the User
model
Add the UserAcl
trait in your User
model.
namespace App;
...
use coucounco\LaravelAcl\Traits\UserAcl;
class User extends Model {
use UserAcl;
...
}
3.2) Add the acl column in the users
table
Create a new migration file to update the users
table
php artisan make:migration add_acl_in_users_table --table=users
And add the new column
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddAclInUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->text('acl')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('acl');
});
}
}
By default the name of this column is
acl
, but you can change it by updatingmodel.user.attributeName
in theconfig/acl/users.php
file and in this migration file.
4) Configure ACL for groups
Optionnaly you can enable group acl.
To enable this feature, you have to edit model.user.enableAcl
it in the config/acl/users.php
file and do the following instructions.
If you don't want direct acl on user, you can jump to the next chapter.
4.1) Set up database tables
To enable the acl for groups, you have to create some more tables or to update your existing tables.
You need a groups
table and the pivot table group_user
to create the ManyToMany relation.
(it's okay if you have different naming)
If you need to create these tables please follow the chapter 4.1.1 else follow the 4.1.2
4.1.1) Create tables
Do not create these tables if you already have similar grouping table with a ManyToMany relation to
User
.
Create a new migration file to create the groups
table
php artisan make:migration create_groups_table
with the following content :
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateGroupsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('groups', function (Blueprint $table) {
$table->bigIncrements('id');
$this->string('name');
$this->text('acl')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('groups');
}
}
The name of the
acl
column can be changed by updatingmodel.group.attributeName
in theconfig/acl/users.php
file and in this migration file.
Add a new migration file to create the pivot table named group_user
php artisan make:migration create_group_user_table
with the following content :
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateGroupUserTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('group_user', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('group_id');
$table->foreign('user_id')
->references('id')->on('users');
$table->foreign('group_id')
->references('id')->on('groups');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('group_user');
}
}
That's all for database table creation.
4.1.2) Update tables
Add the acl column in your grouping table.
Create a new migration file to update your grouping table.
Be sure to have the right name for the table.
php artisan make:migration add_acl_in_groups_table --table=groups
And add the new column
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddAclInUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('groups', function (Blueprint $table) {
$table->text('acl')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('groups', function (Blueprint $table) {
$table->dropColumn('acl');
});
}
}
By default the name of this column is
acl
, but you can change it by updatingmodel.group.attributeName
in theconfig/acl/users.php
file and in this migration file.
That's all for database table update.
4.2) Update the group model
Add the GroupAcl
trait in your Group model. You also need to add the relationship to the User
model
namespace App\Models;
...
use coucounco\LaravelAcl\Traits\GroupAcl;
class Group extends Model
{
use GroupAcl;
...
public function users() {
return $this->belongsToMany('App\User');
}
}
4.3) Update the User
model
Add the relation into the User
model.
If your group table has a different name, it's not a problem. You just have to update model.group.relationship
and set this name on the relation function
in the the config/acl/users.php
file
namespace App;
class User extends Model {
...
public function groups() {
return $this->belongsToMany('App\Group');
}
}
5) Enjoy !
Everthing is ready, now jump to the documentation section to learn more about laravel-acl.
Documentation
This chapter explain how laravel-acl works and describe the available tools (helpers, middleware, ...).
Define permissions and roles
Permission and roles are managed in a hard coded way in the config/acl/users.php
file. This choice was made to simplify the use
and to avoid database query as much as possible.
Permissions
You can easly add permissions by adding a new entry in the permissions
array in the config/acl/users.php
file.
The key is the name of the permission and the value is the identifier
It's mandatory to have the superadmin
permission with the identifier set as 0
.
You can manage every other permissions the way you want.
'permissions' => [
'superadmin' => 0,
'user' => 1,
'group' => 2,
'page' => 3,
'run_page_import' => 9,
],
Roles
A role is a preset of permissions. You can manage roles with the roles
array in the config/acl/users.php
file.
The key is the name of the role and the value is the ACL.
'roles' => [
'admins' => "1",
'user' => "4110",
],
ACL
What is the ACL ?
It's a string value that define the permissions of a user or a group.
This value is stored by default in the acl
column in the users
table and in the group table.
Let's take the following ACL as a exemple.
"1000003410"
If we have defined the following permissions.
'permissions' => [
'superadmin' => 0,
'user' => 1,
'group' => 2,
'page' => 3,
'run_page_export' => 8,
'run_page_import' => 9,
],
ACL are red from the right to the left.
What does each digit means ?
- The first digit
"0"
of the ACL"1000003410"
represent the permission with the0
identifier. In our case it's thesuperadmin
permissions. - The 2nd digit
"1"
represent the permission with the1
identifier. (it's theuser
permission). - The 4th digit
"3"
represent thepage
permission. - The 8th
"0"
represent therun_page_export
permission. - The last digit (the 9th)
"1"
represent therun_page_import
permission.
But, what are those values "0"
, "1"
, "2"
, "3"
, "4"
on each digit ?
These values define the access level for the given permission
So, to describe the ACL "1000003410"
, the user has the following permissions/restrictions :
- The user is not a
superadmin
; - The user has the read access on the
user
permission; - The user has the delete acces on the
group
permission; - The user has the update access on the
page
permission; - The user can't perform
run_page_export
; - And the user is allowed to perform
run_page_import
.
You know everything about the permissions, roles and ACL. Jump to the next chapter to learn how to grant and revoke permissions
Grant and revoke permissions
To a User
How to give the superadmin permission to a user :
$user->grantPermission('superadmin', ACL_ALLOW);
$user->save();
If you don't save, the permission will not persist in the database.
How to give the read access to the group
permission to a user :
$user->grantPermission('group', ACL_READ);
$user->save();
How to give the delete access to the page
permission to a user :
$user->grantPermission('page', ACL_DELETE);
$user->save();
How to grant many permissions at once :
$user->grantPermissions([
'page' => ACL_READ,
'user' => ACL_UPDATE
]);
$user->save();
How to revoke a permission :
$user->revokePermission('user');
$user->save();
or you can also grant the ACL_NONE
or ACL_DENY
level.
$user->grantPermission('user', ACL_DENY);
$user->save();
How to revoke many permissions:
$user->revokePermissions(['user', 'group']);
$user->save();
How to revoke all permissions:
$user->revokePermissions();
$user->save();
To a group
It works the same way as with the user.
$group->grantPermission('user', ACL_READ);
$group->save();
$group->grantPermissions([
'user' => ACL_READ,
'page' => ACL_UPDATE,
'run_page_export' => ACL_ALLOW
]);
$group->save();
$group->revokePermission('user');
$group->save();
$group->revokePermissions(['user', 'run_page_export']);
$group->save();
Now that you know how to grant and revoke permissions to a user or a group, you need to learn how to check permissions for a user.
Checking access
This chapter describe every way to check if a user has the permissions to acces pages or perform actions.
Gate
You can use Gate facade provided by laravel.
Gate::allows('user', [ACL_CREATE]);
User model
You can use the Laravel can
method of the User
to check a permission.
Check if the user can read page :
$hasPermission = auth()->user()->can('page', [ACL_READ]);
It will return true if the user is able to read pages else it return false.
Check if the user can edit user in the context of the given group :
$group = Group::find(1);
$hasPermission = auth()->user()->can('page', [ACL_READ, $group]);
It will return true only if the user has the acces granted by the given group else it return false.
It's usefull to manage access to entity that are in relation with a specific group.
Check if the user can update the page in the context of many groups :
$group1 = Group::find(1);
$group2 = Group::find(12);
$hasPermission = auth()->user()->can('page', [ACL_READ, collect([$group1, $group2])]);
The 2nd parameter (groups)" must be a collection
Illuminate\Support\Collection
.
Middleware
You can use the acl
middleware provided by laravel-acl to protect routes or a whole resource directly in the route files (routes/web.php
).
Restrict the access to user with a given permission and level
Route::get('users/index', 'UserController@index')->name('users.index')->middleware('acl:user:1');
This route will allow the acces only to user who have the
user
permission with theACL_READ
level.
Restrict the access to user with any of the given permission and level
Route::get('users/index', 'UserController@index')->name('users.index')->middleware('acl:user:1|group:1');
This route will allow the acces only to user who have the
user
permission with theACL_READ
level or thegroup
permission with theACL_READ
level.
Blade
It's usefull to be able to hide some buttons in your blade view. To achieve this, you can use some directive provided by Laravel.
The @can
blade directive
@can('user', [ACL_READ])
allow
@else
denied
@endcan
It's the same as writing
@if(auth()->user()->can('user', [ACL_READ]))
allow
@else
denied
@endif
The @cannot
blade directive
@cannot('user', [ACL_READ])
denied
@else
allow
@endcannot
The @canany
blade directive
@canany(['user', 'page'], [ACL_READ])
The user has page or user permisson with a read level
@elsecanany(['group'], ACL_READ)
Or the user has the group permission with a read level
@else
denied
@endcannot
Helper
Checking permissions
Checking if the user can read page
acl_has_permission($user, 'page', ACL_READ)
Retrieve permissions and roles
You can retrieve all permissions with the helper method :
$permissions = acl_permissions()
Get permissions for another acls, just pass the acls name in parameter
acl_permissions('members')
You can retrieve all roles with the helper method :
$roles = acl_roles()
Get roles for another acls, just pass the acls name in parameter
acl_permissions('members')
The strict
option
Sometimes, you will probably want to check if the user have strictly a permission.
What does this mean ?
Exemple:
$user1
have thesuperadmin
permission$user2
have theis_manager
permission
So when you check if the $user1
have the is_manager
permission :
$user1->can('is_manager');
this will return
true
even if he don't have theis_manager
permission because he issuperadmin
.
It's possible to check permissions with the strict parameter.
$user1->can('is_manager', ACL_STRCT);
this will return
false
even if the user issuperadmin
.
$user2->can('is_manager', ACL_STRCT);
this will return
true
because$user2
have theis_manager
permission.