Installation:
composer require kordy/auzo-tools
Register the service provider in config/app.php:
Kordy\AuzoTools\AuzoToolsServiceProvider::class,
Publish Config:
php artisan vendor:publish --provider="Kordy\AuzoTools\AuzoToolsServiceProvider" --tag="config"
This generates config/acl.php for defining authorization rules.
First Use Case:
Define a basic policy in config/acl.php:
return [
'abilities' => [
'post.update' => function($user, $ability, $model) {
return $user->id === $model->user_id;
},
],
];
Register policies in AppServiceProvider@boot:
\AuzoToolsPermissionRegistrar::registerPermissions(config('acl'));
Usage: Check authorization in controllers/views:
if (auth()->user()->can('post.update', $post)) {
// Authorized action
}
Policy Definition:
user->id === 1).App\Policies\PostPolicy).
Example:
class PostPolicy {
public function updateOwner($user, $post) {
return $user->id === $post->user_id;
}
}
Configure in config/acl.php:
'abilities' => [
'post.update' => 'App\Policies\PostPolicy@updateOwner',
],
Dynamic Abilities:
Use GenerateAbilities to auto-generate CRUD abilities for models:
$abilities = GenerateAbilities::modelAbilities('post');
// Returns: ['post.index', 'post.create', ..., 'post.destroy']
Route-Level Authorization: Apply middleware to routes:
Route::get('/profile', function() {})->middleware('auzo.acl:profile.view');
Or auto-detect via named routes:
Route::get('/profile', 'ProfileController@show')
->name('profile.show')
->middleware('auzo.acl'); // Checks 'profile.show' ability
Field-Level Policies:
Restrict model fields dynamically using ModelFieldsPolicy trait:
class Post extends Model {
use ModelFieldsPolicy;
protected $abilityFix = 'post.show'; // Auto-checks `post.show.fieldname`
}
Override getFillableFields() to customize behavior:
public function getFillableFields($user) {
return $user->can('post.update') ? ['title', 'content'] : ['title'];
}
Validation Integration:
Use auzo.can rule in Form Requests:
public function rules() {
return [
'content' => 'required|auzo.can:post.update.content',
];
}
Middleware Parameter Mismatch:
auzo.acl:ability, ensure the ability name matches exactly (e.g., post.update vs. post_update).GenerateAbilities to standardize naming.Model Fields Policy Overhead:
ModelFieldsPolicy trait adds runtime checks for every field access.public function toArray($user) {
$fields = $this->getVisibleFields($user);
return array_intersect_key($this->attributesToArray(), array_flip($fields));
}
Config Overrides:
before/after callbacks in config/acl.php run globally. Misuse can break authorization logic.before for global checks (e.g., "admin-only" routes) and after for logging.Deprecated Laravel Versions:
spatie/laravel-permission instead).Ability Name Collisions:
user.index.name) may conflict with manual definitions.custom.user.index).Log Authorization Decisions:
Add an after callback to config/acl.php:
'after' => [
function($user, $ability, $result) {
\Log::debug("Ability $ability: " . ($result ? 'Allowed' : 'Denied'));
},
],
Validate Middleware: Test route middleware with:
Route::get('/test', function() { return 'OK'; })->middleware('auzo.acl:test.ability');
Use php artisan route:list to verify middleware is applied.
Field Policy Debugging:
Temporarily override getVisibleFields() to log denied fields:
public function getVisibleFields($user) {
$fields = parent::getVisibleFields($user);
\Log::debug("Denied fields: " . implode(', ', array_diff($this->getFillable(), $fields)));
return $fields;
}
Custom Ability Generators:
Extend GenerateAbilities to support nested resources:
class CustomGenerator extends GenerateAbilities {
public function nestedAbilities($parent, $child) {
return ["{$parent}.{$child}.index", "{$parent}.{$child}.create"];
}
}
Dynamic Policy Classes: Load policies dynamically based on user roles:
$policyClass = config("acl.policies.{$user->role}");
$this->app->bind($policyClass, function() use ($user) {
return new $policyClass($user);
});
Integration with Gates: Combine with Laravel’s native Gates for hybrid authorization:
Gate::define('post.update', function($user, $post) {
return $user->can('post.update', $post) || $user->isAdmin();
});
API Rate Limiting:
Use after callbacks to track failed attempts:
'after' => [
function($user, $ability, $result) {
if (!$result) {
$user->increment('failed_authorization_attempts');
}
},
],
How can I help you explore Laravel packages today?