If you worked with user rights in Laravel, you probably used policy classes.
In some situations, the policy methods work on the same principle - the conditions work very similar:
I made a small package that provides access to the abstract class MagicPolicy. Inherit your policy classes from it and your code will be reduced, as well as it will become more convenient to support.
In the example shown in the image above, the final code (when using my package) will be as follows:
Laravel Policy Permission Check
Installing and connecting the package
You must install the package using composer:
composer require sarvarov/laravel-policy-permission-check
After that, all you need to do is to extend Sarvarov\LaravelPolicyPermissionCheck\MagicPolicy in your policy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15<?php namespace App\Models\Policies; use App\Models\Auth\User; use App\Models\Post; use Illuminate\Auth\Access\HandlesAuthorization; use Sarvarov\LaravelPolicyPermissionCheck\MagicPolicy; class PostPolicy extends MagicPolicy { use HandlesAuthorization; /* ... */ }
Magic methods
If you just check whether the user has access to an action, the package will find the appropriate permission itself, taking the method name as the basis.
For example, if you inherit from MagicPolicy, you can delete the following policy method (it is unnecessary):
public function update(User $user, Post $post)
{
return $user->can('update posts');
}
By default, it tries to find the resolution using the following key: event + space + plural model:
view any posts
view posts
create posts
update posts
delete posts
# etc...
If you use a different rules for permission names, change them by editing the following settings:
- permission.naming_rules.subject_plural - whether to make the model name plural.
Example (if set false): will be view post, not view posts (as default). - permission.naming_rules.delimiters.between_words - word separator in the permission name.
Example (if set -): will be view-any blog-posts, not view any blog posts (as default). - permission.naming_rules.delimiters.between_subject_and_action - delimiter between the action and the model.
Example (if set .): will be posts.view, not posts view (as default). - permission.naming_rules.key_pattern - the order of elements in the permission key.
Example (if set {subject}{delimiter}{action}): will be posts view any, not view any posts (as default).
For example, if your application uses the dot notation in the keys of permissions, then you need to change the following settings:
- permission.naming_rules.delimiters.between_words - set to ..
- permission.naming_rules.delimiters.between_subject_and_action - set to -.
- permission.naming_rules.key_pattern - set to {subject}{delimiter}{action}.
Result will be:
# Before
view any posts
# After
posts.view-any
This way, you can adapt the package to the naming rules of permissions of your app.
Additional checks
If, in addition to the permission check, you need to perform some additional checks for passing conditions - you need to create the appropriate method in the policy class.
In this method you can run the checkPermission() helper:
- In the first argument, pass $user.
- In the second argument, pass the event (if you don't pass it, the permission will be checked based on the name of the method being called).
1 2 3 4 5 6 7 8protected function delete(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkPermission($user, 'delete own posts'); } return $this->checkPermission($user); }
Proxy methods
If you repeat the code of several methods, you can use proxy methods.
To do this, you need to create an array - the protected $proxies property in the policy class.
The key of elements in this array is the name of the method where need to "redirect" from the called method. The value of these elements will be an array of names of proxy methods (redirect from methods):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44// Было: class PostPolicy extends MagicPolicy { use HandlesAuthorization; protected function update(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkPermission($user, 'update own'); } return $this->checkPermission($user); } protected function delete(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkPermission($user, 'delete own'); } return $this->checkPermission($user); } } // Стало: class PostPolicy extends MagicPolicy { use HandlesAuthorization; protected $proxies = [ 'manage' => ['update', 'delete'], ]; protected function manage(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkProxiedPermission($user, 'own'); // checks for `update own posts` and `delete own posts` } return $this->checkPermission($user); // checks for `update posts` and `delete posts` } }
By default, permissions are compared by proxy method names, but you can override this by adding :false to the key in the $proxies property element(s):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17class PostPolicy extends MagicPolicy { use HandlesAuthorization; protected $proxies = [ 'manage:false' => ['update', 'delete'], ]; protected function manage(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkProxiedPermission($user, 'own'); // checks for `manage own posts` always } return $this->checkPermission($user); // checks for `manage posts` always } }
Managing settings
To change the package configuration, you must create a file /config/permission.php. Inside this file, you need to return an array of settings.
All parameters can be found in the package files: MagicPermission.php and PermissionCheckHelper.php.
Did you like what you just read?
Give me a "high five" by clicking once, or applaud with quick taps to show how much you liked the material.
Comments