نظام تخويل الموارد المتقدم في Laravel. الجزء 2. البوابات والسياسات

المقدمة


مرحبا عزيزي خابروفشان.
أواصل سلسلة مقالتي حول ترخيص الموارد المتقدمة في Laravel. لفهم أفضل لما سيتم مناقشته في هذه المقالة - تحتاج إلى قراءة الجزء الأول .


بادئ ذي بدء ، سأكرر بإيجاز بيان المشكلة: هناك عدد كبير من النماذج. من الضروري تصميم نظام مرن وقابل للتوسيع بسهولة لتفويض إجراءات المستخدم حسب دوره.
في هذا الجزء ، سنتحدث عن تكوين سياسة الارتباط <=> بوابة. ويقترح أيضًا أحد الخيارات لكتابة حقوق المستخدم في قاعدة البيانات.


وبالطبع ، سأوضح على الفور أن المادة مصممة لممارسة المبرمجين ، وسيكون من الصعب على المطور المبتدئ فهمها.



الجزء 3. السياسات والبوابات


الجزء النظري


يمكن العثور على الكثير من المواد على الإنترنت حول الموضوع - "ماذا تختار السياسة أو البوابة ؟". لبعض الوقت ، وصلت أيضًا إلى خطأ مماثل أنك بحاجة إلى اختيار شيء ما. ولكن في النهاية توصلت إلى الاستنتاج - هذان رابطان من نفس السلسلة ، وهما الأكثر استخدامًا بالتزامن.
في Laravel ، هناك اتجاهان رئيسيان لتحديد هذه الحزمة - يدوي وتلقائي. لن أفكر يدويًا ، نظرًا لأن دعم هذا النوع من الحزم سيتطلب جهودًا مبرمجة بشكل غير متناسب أكثر من إعداد حزمة تلقائية.


— , () . (Gate) — . — , . , . , app. . app/Models.


Gate::guessPolicyNamesUsing('callback'). , boot() App\Providers\AuthServiceProvider( ).



Gate


(callback), guessPolicyNamesUsing() , . . : Policy . , , Laravel ( ). SuperAdmin , , — super-admin . — .
PHP 7.4 . 7.4 .


<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->defineSuperAdmin();
        $this->defineAutoDiscover();
    }

    private function defineAutoDiscover()
    {
        Gate::guessPolicyNamesUsing(function ($class) {
            return str_replace("\\Models\\", "\\Policies\\" , $class) . 'Policy';
        });
    }

    private function defineSuperAdmin()
    {
        Gate::before(function($user) {
            return $user->hasRole('super-admin') ? true : null;
        });
    }
}

Policy


, , . . :


    php artisan make:policy PostPolicy --model=Models/Post

. . , DRY,- , . , . , getModelClass() . , ( ). . (import export — )


<?php
protected function resourceAbilityMap()
{
    return [
        'index' => 'viewAny',
        'show' => 'view',
        'create' => 'create',
        'store' => 'create',
        'edit' => 'update',
        'update' => 'update',
        'destroy' => 'delete',
        'import' => 'import',
        'export' => 'export',
    ];
}

— , . , . . Spatie. laravel-permission. , — , , . , , . — , $user->can() $user->hasRole(), Spatie\Permission\Traits\HasRoles


(Models\User)

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use Notifiable;
    use HasRoles;

    /**     */
}

, (Admin User, ) — HasRoles, .
.


(ModelPolicy)

<?php

namespace App\Policies;

use App\Models\User;
use App\Models\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Database\Eloquent\Model;

abstract class ModelPolicy
{
    use HandlesAuthorization;

    abstract protected function getModelClass(): string;

    public function viewAny(User $user)
    {
        return $user->can('view-any-' . $this->getModelClass());
    }

    public function view(User $user, Post $model)
    {
        return $user->can('view-' . $this->getModelClass());
    }

    public function create(User $user)
    {
        return $user->can('create-' . $this->getModelClass());
    }

    public function update(User $user, Post $model)
    {
        return $user->can('update-' . $this->getModelClass());
    }

    public function delete(User $user, Post $model)
    {
        return $user->can('delete-' . $this->getModelClass());
    }
}

$user->can('ability') . . ''-' ', — ( ). (SoftDelete). , .
. Post getResourceName() .


(PostPolicy)

<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;

class PostPolicy extends ModelPolicy
{
    protected function getModelClass(): string
    {
        return Post::class;
    }

    public function import(User $user)
    {
        return $user->can('import-' . $this->getModelClass());
    }

    public function export(User $user, Post $model)
    {
        return $user->can('export-' . $this->getModelClass());
    }
}

, import() , . — . . , .


, , . .


4. (Seeding)


, . .
spatie/laravel-permission, . .
:


    composer require spatie/laravel-permission
    php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

(seeder)


    php artisan make:seeder PermissionsSeeder

run() database/seeds/DatabaseSeeder.php. PermissionsSeeder .


(DatabaseSeeder)

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
         $this->call(PermissionsSeeder::class);
    }
}

, — PermissionsSeeder. database/data php . :


    role => model => action

// (permissions_roles.php)

<?php

return [
    'admin' => [
        'App\\Models\\Post' => [
            'view',
            'view-any',
            'create',
            'update',
            'delete',
            'import',
            'export',
        ],
    ],
    'App\\Models\\Post' => [
        'post' => [
            'view',
            'view-any',
        ],
    ],
];

. , , — .


(PermissionsSeeder)


<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class PermissionsSeeder extends Seeder
{
    private $data = [];

    public function run()
    {
        $this->loadData();
        $this->seedRoles();
    }

    public function loadData(): void
    {
        $this->data = require_once database_path("data/permissions_roles.php");
    }

    private function seedRoles(): void
    {
        Role::create(['name' => 'super-admin', 'guard_name' => 'api']);

        foreach ($this->data as $roleName => $perms) {
            $role = Role::create(['name' => $roleName, 'guard_name' => 'api']);
            $this->seedRolePermissions($role, $perms);
        }
    }

    private function seedRolePermissions(Role $role, array $modelPermissions): void
    {
        foreach ($modelPermissions as $model => $perms) {
            $buildedPerms = collect($perms)
                ->crossJoin($model)
                ->map(function ($item) {
                $perm = implode('-', $item); //view-post
                Permission::findOrCreate($perm, 'api');

                return $perm;
            })->toArray();

            $role->givePermissionTo($buildedPerms);
        }
    }
}

, - . , , . , , .
, :


  • run() .
  • loadData() database/data $data
  • seedRoles() . , $data, . 'super-admin' , , .. ( AuthServiceProvider).
  • seedRolePermissions() , , «» , (permission). . () — findOrCreate(), laravel-permissions. , , .

, . :


    php artisan migrate --seed

. ! , :


  1. (Model).
  2. (Controller) ModelController.
  3. (Policy) ModelPolicy.
  4. .

, (. 1) (. ).


هذا كل شئ حتى الان. آمل أن تكون هذه المقالة مفيدة. وإذا كان أحد الأشخاص مهتمًا بالتوليف الدقيق لحقوق وقيود المستخدمين ، أي حق المستخدم في مشاهدة / تغيير سمة معينة للنموذج - تتم
مناقشة هذا في الجزء الثالث .


All Articles