Eloquent Guardian is a simple permissions system for your users.
It's simple. It has to be simple. Don't bother using gates or anything of that complicate stuff. You can store permissions, you can track them and you can check your users when you need to: either it's from the model or within a middleware.
Install the package:
$ composer require rennokki/guardian
If your Laravel version does not support package discovery, add this line in the providers
array in your config/app.php
file:
Rennokki\Guardian\GuardianServiceProvider::class,
Publish the config file & migration files:
$ php artisan vendor:publish
Migrate the database:
$ php artisan migrate
Add the HasPermissions
trait to your Eloquent model:
use Rennokki\Guardian\Traits\HasPermissions;
class User extends Model {
use HasPermissions;
...
}
- String Type is just a string, it's not related to any model. It is good for permissions that holds accessing abilities or features.
$user->allow('access.dashboard');
- Global Type is related to a model, but not to a specific one. It can control any model with any ID if set.
$user->allow('edit', Post::class);
- Global Specific Type is related to a specific model. It cannot control any other model than this specific one.
$user->allow('edit', App\Post::class, 'post_id_here');
You can check permissions within the model using can()
, cannot()
or cant()
.
$user->can('access.dashboard');
$user->cannot('sell.products');
$user->cant('sell.products'); // alias to cannot()
Allowing or Unprohibiting produces a grant access to that permission.
$user->allow('cloning');
$user->unprohibit('cloning'); // same thing
Disallowing or Prohibiting permissions can be done whenever. The result will always be the same: a denied access.
$user->disallow('commenting');
$user->prohibit('commenting'); // produces the same thing.
Let's say you have a Post
class and the user is only allowed to edit or delete only his own posts. Using this way, whenever you check for a Global Type, it will return false, but not if you check for Specific Type.
$user->allow('edit', Post::class, 'his_post_id');
$user->allow('delete', Post::class, 'his_post_id');
$user->can('edit', Post::class); // false
$user->can('edit', Post::class, 'his_post_id'); // true
Now let's say you have chat rooms. And you want to give an user the permission to see any chat room, but not a specific one.
$user->allow('view', ChatRoom::class);
$user->disallow('view', ChatRoom::class, 'this_id_is_hidden');
$user->can('view', ChatRoom::class); // true
$user->cannot('view', ChatRoom::class, 'this_id_is_hidden'); // true
Make sure you check for Specific Types before the Global Types. Otherwise, you will give access to a hidden chat room that shouldn't be accessible for that user.
$user->permissions();
$user->allowedPermissions();
$user->prohibitedPermissions();
You can use the methods within the model as-is, or you can use a middleware to filter permissions. For this, you should add the middleware to your $routeMiddleware
array from app\Http\Kernel.php
'guardian' => \Rennokki\Guardian\Middleware\CheckPermission::class,
After this, you can use it in your routes to filter permissions automatically and throw specific exceptions when something occurs.
- String Middleware
Route::get('/admin', 'AdminController@ControlPanel')->middleware('guardian:access.adashboard');
- Global Type
Route::post('/admin/products', 'AdminController@CreateProduct')->middleware('guardian:create,App\Product');
- Global Specific Type
Route::patch('/admin/{post_id}', 'AdminController@EditPost')->middleware('guardian:edit,App\Post,post_id');
Note: Instead of putting a specific Post ID, you have just to indicate where the ID of that model will be placed in the route URL.
Rennokki\Guardian\Exceptions\PermissionException
, if the authenticated user doesn't have permissions.Rennokki\Guardian\Exceptions\RouteException
, if the passed route parameter is non-existent.
You can access permission()
, modelType()
and modelIdPlaceholder()
methods within the exception to handle your exception further, at this point.