kordy / auzo-tools
Helper functions that makes it very easy to manage Laravel authorization and provides a central authorization management. Compatible with Laravel versions 5.1, 5.2, and 5.3
Installs: 280
Dependents: 1
Suggesters: 0
Security: 0
Stars: 4
Watchers: 3
Forks: 0
Open Issues: 1
Type:package
Requires
- laravel/framework: ^5.1
Requires (Dev)
- phpunit/phpunit: ^4.0|^5.0
This package is auto-updated.
Last update: 2021-05-06 01:54:02 UTC
README
This package is a set of tools for Laravel 5.1, 5.2, and 5.3 to facilitate authorize management for your Laravel project or package. You can use AuzoTools to manage authorization in your project, or to provide configurable authorization option for your package users.
Tools included:
- Manage Laravel authorization.
- Automatic abilities generator for models.
- Route authorize middleware.
- Controller authorize validation rule.
- Model fields policy.
Installation
You can install the package via composer:
composer require kordy/auzo-tools
This service provider must be installed.
// config/app.php 'providers' => [ ... Kordy\AuzoTools\AuzoToolsServiceProvider::class, ];
You can publish the translations with:
php artisan vendor:publish --provider="Kordy\AuzoTools\AuzoToolsServiceProvider" --tag="translations"
You can publish the config file with:
php artisan vendor:publish --provider="Kordy\AuzoTools\AuzoToolsServiceProvider" --tag="config"
Usage
Manage Laravel authorization
AuzoTools can help you manage abilities for any number of resources and manage restriction policies for who can access them using functions as parameters. You can use AuzoTools to manage authorization in your project, or to provide configurable authorization option for your package users.
Parameter functions can act as policies, so when AuzoTools is evaluating a user access to a resource/model record, it will pass these information to the function you specified as a parameter, your function will evaluate user information against the resource they want to access, then return a boolean decision to allow the user access or not.
See an example at the test file
You have two ways to define policies, either callbacks or a dedicated class methods.
1. Callbacks policies
Create config file as this one:
// config/acl.php return [ 'before' => [ function($user, $ability) { return $user->id == 1; } ], 'abilities' => [ 'post.update' => [ function($user, $ability, $model) { return $user->id == 3; }, ['or' => function ($user, $ability, $model) { return $user->id == 2; }], ], 'post.destroy' => [ function ($user, $ability, $model) { return $user->id == 2; }, ], ], // use this to log or monitor authorization given to users // you may not modify the result of the authorization check from an after callback 'after' => [ function ($user, $ability, $result, $arguments = null) { if ($result) { \Log::info("Authorization Log: User $user->name ($user->email) is granted access to ability $ability at ".date('d-m-Y H:j')); } else { \Log::info("Authorization Log: User $user->name ($user->email) is forbidden to access ability $ability at ".date('d-m-Y H:j')); } }, ], ];
2. Dedicated class methods
Create config file as this one:
// config/acl.php return [ 'before' => [ 'App\MyPolicyClass@isAdmin' ], 'abilities' => [ 'post.update' => [ 'App\MyPolicyClass@postOwner', ['or' => 'App\MyPolicyClass@isModerator'] ], 'post.destroy' => [ 'App\MyPolicyClass@isModerator' ], ], // use this to log or monitor authorization given to users // you may not modify the result of the authorization check from an after callback 'after' => [ 'App\MyPolicyClass@monitor' ], ];
Create a policy class that holds policies methods
<?php namespace App; class MyPolicyClass { /** * Check if user is admin * * @param $user * @param $ability * @return bool */ public function isAdmin($user, $ability) { return $user->id == 1; } /** * Check if user is moderator * * @param $user * @param $ability * @return bool */ public function isModerator($user, $ability) { return $user->role == 'moderator'; } /** * Check if user is post owner * * @param $user * @param $ability * @return bool */ public function postOwner($user, $ability, $post) { if ($post instanceOf Post) { return $user->id == $post->user_id; } // If middleware passed you the user request instead of the model // instance, get the resource information from the request if ($post === null || $post instanceof Request) { $postId = request()->route('id'); $post = Post::find($postId); return $user->id == $post->user_id; } } /** * Run authorization monitor, see storage/logs/laravel.log * * @param $user * @param $ability */ public function monitor($user, $ability, $result, $arguments = null) { if ($result) { \Log::info("Authorization Log: User $user->name ($user->email) is granted access to ability $ability at " . date('d-m-Y H:j')); } else { \Log::info("Authorization Log: User $user->name ($user->email) is forbidden to access ability $ability at " . date('d-m-Y H:j')); } } }
Finally:
Load Abilities to Laravel Gate at boot by runing the \AuzoToolsPermissionRegistrar::registerPermissions($abilities_policies)
in your service provider
// app/Providers/AppServiceProvider.php public function boot() { // Load abilities to Laravel Gate $abilities_policies = config('acl'); \AuzoToolsPermissionRegistrar::registerPermissions($abilities_policies); }
Now you can authorize users at any point in your project or package:
$user->can('post.show', $post) // or $user->cannot('post.update', $post) // or for current logged in user Gate::allows('post.update', Post::findOrFail($postId));
More details: https://laravel.com/docs/master/authorization#authorizing-actions-using-policies
Automatic abilities generator
Give it a name and it automatically generates abilities names matching the default route resource names or custom name fix.
Generate CRUD abilities for a model
$generator = GenerateAbilities::modelAbilities('testuser'); $generated_abilities = $generator->model_crud_abilities;
This will generate ability name per each route path:
[ 'index' => 'testuser.index', 'create' => 'testuser.create', 'store' => 'testuser.store', 'show' => 'testuser.show', 'edit' => 'testuser.edit', 'update' => 'testuser.update', 'destroy' => 'testuser.destroy', ]
In config/auzo-tools.php, you can modify the CRUD for what route paths to generate for:
'crud' => ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy']
Generate CRUD abilities for a model fields
It can also generate full list of abilities for a model fields like so:
$generator = GenerateAbilities::fieldsAbilities(App\User::class) $generated_fields_abilities = $generator->fields_crud_abilities;
This will generate ability name per each model column per each model route path:
[ 'id' => [ 'index' => 'user.index.id', 'create' => 'user.create.id', 'store' => 'user.store.id', 'show' => 'user.show.id', 'edit' => 'user.edit.id', 'update' => 'user.update.id', 'destroy' => 'user.destroy.id' ], 'name' => [ 'index' => 'user.index.name', 'create' => 'user.create.name', 'store' => 'user.store.name', 'show' => 'user.show.name', 'edit' => 'user.edit.name', 'update' => 'user.update.name', 'destroy' => 'user.destroy.name' ], 'email' => [ 'index' => 'user.index.email', 'create' => 'user.create.email', 'store' => 'user.store.email', 'show' => 'user.show.email', 'edit' => 'user.edit.email', 'update' => 'user.update.email', 'destroy' => 'user.destroy.email' ], 'password' => [ 'index' => 'user.index.password', 'create' => 'user.create.password', 'store' => 'user.store.password', 'show' => 'user.show.password', 'edit' => 'user.edit.password', 'update' => 'user.update.password', 'destroy' => 'user.destroy.password' ], 'remember_token' => [ 'index' => 'user.index.remember_token', 'create' => 'user.create.remember_token', 'store' => 'user.store.remember_token', 'show' => 'user.show.remember_token', 'edit' => 'user.edit.remember_token', 'update' => 'user.update.remember_token', 'destroy' => 'user.destroy.remember_token' ], 'created_at' => [ 'index' => 'user.index.created_at', 'create' => 'user.create.created_at', 'store' => 'user.store.created_at', 'show' => 'user.show.created_at', 'edit' => 'user.edit.created_at', 'update' => 'user.update.created_at', 'destroy' => 'user.destroy.created_at' ], 'updated_at' => [ 'index' => 'user.index.updated_at', 'create' => 'user.create.updated_at', 'store' => 'user.store.updated_at', 'show' => 'user.show.updated_at', 'edit' => 'user.edit.updated_at', 'update' => 'user.update.updated_at', 'destroy' => 'user.destroy.updated_at' ] ]
Saving generated abilities as json string to a file
Encodes the results in a json string and save it to given file path:
$file_path = config_path('abilities/generated_abilities.json'); // This will faltten the output array GenerateAbilities::fullCrudAbilities($model)->writeToFile($file_path); // This will not faltten the output array GenerateAbilities::fullCrudAbilities($model)->writeToFile($file_path, false);
Flatten Output:
[ "user.index", "user.create", "user.store", "user.show", "user.edit", "user.update", "user.destroy", "user.index.id", "user.create.id", "user.store.id", "user.show.id", "user.edit.id", "user.update.id", "user.destroy.id", "user.index.name", "user.create.name", "user.store.name", "user.show.name", "user.edit.name", "user.update.name", "user.destroy.name", "user.index.email", "user.create.email", "user.store.email", "user.show.email", "user.edit.email", "user.update.email", "user.destroy.email", "user.index.password", "user.create.password", "user.store.password", "user.show.password", "user.edit.password", "user.update.password", "user.destroy.password", "user.index.remember_token", "user.create.remember_token", "user.store.remember_token", "user.show.remember_token", "user.edit.remember_token", "user.update.remember_token", "user.destroy.remember_token", "user.index.created_at", "user.create.created_at", "user.store.created_at", "user.show.created_at", "user.edit.created_at", "user.update.created_at", "user.destroy.created_at", "user.index.updated_at", "user.create.updated_at", "user.store.updated_at", "user.show.updated_at", "user.edit.updated_at", "user.update.updated_at", "user.destroy.updated_at" ]
Route authorize middleware
This is a Route middleware that can be used with routes or in the Http controllers to check user authorization before accessing the requested resource.
use it with parameter:
Route::get('user-profile-test', function (){ return 'hello there'; })->middleware('auzo.acl:user-profile');
This will check if the user has authorize ability for 'user-profile'
Automatic authorization check
Route::get('user-profile-test/{id}', 'Controller@action') ->name('user.profile.test')->middleware('auzo.acl');
With named route
, you might use the middleware with no parameter for automatic
authorization.
- It will check if user is authorized for the route name
user.profile.test
- If route does not have name, then it will check against the
Controller@action
Controller authorize validation rule
This is a custom validation rule auzo.can
that check if the user is authorized
against a passed parameter for the field ability name.
$v = Validator::make($data, [ 'someField' => 'auzo.can:test.ability.someField', ]);
if user is not authorized, a validation error is generated, to modify the generated
error message, modify resource/lang/vendor/auzo-tools/en/validation.php
:
return [ 'can' => 'You are not authorized to modify :attribute !', ];
Model fields policy
Very useful for API, where you can change hidden, fillable, and guarded columns based on user authorization before the model data is being sent to the user.
First make sure you added the ModelFieldsPoilcy trait to your models.
use Kordy\AuzoTools\Traits\ModelFieldsPolicy;
Example: In your model files add this after class declaration:
class SomeModel extends Model { use Kordy\AuzoTools\Traits\ModelFieldsPolicy;
Pass the model ability fix, so it checks for each field name attached to the ability fix and check if user is authorized for the generated ability.
So if model has fields name
, email
, password
, and yoe pass user.show
fix,
Then it will check authorization for:
check for the name
field if the user has ability user.show.name
check for the email
field if the user has ability user.show.email
check for the password
field if the user has ability user.show.password
and so on.
Make unauthorized columns hidden
$model->hideFieldsByPolicy('user.show');
Make unauthorized columns not fillable
$model->fillableFieldsByPolicy('user.show');
Make unauthorized columns guarded
$model->guardFieldsByPolicy('user.show');
Contributing
Please see CONTRIBUTING for details.
License
The MIT License (MIT). Please see License File for more information.