Атрибут UsePolicy у Laravel: Явне управління авторизацією

Перекладено ШІ
Оригінал: Laravel News
Оновлено: 12 серпня, 2025
Вам потрібен більший контроль над авторизаційною логікою у Laravel? Дізнайтеся, як атрибут UsePolicy може допомогти зробити ваш код більш зрозумілим та гнучким, а також усунути неоднозначності в авторизаційних перевірках. Читайте далі, щоб відкрити для себе нові можливості для вашого проєкту

Потребуєте перевизначити автоматичне визначення політик Laravel або зробити авторизаційні зв’язки більш прозорими у вашому коді? Атрибут UsePolicy надає пряму можливість контролювати, яка політика обробляє логіку авторизації вашої моделі

Зазвичай Laravel виявляє політики через конвенції в іменах — модель Product автоматично пов'язується з ProductPolicy. Хоча ця конвенція працює добре, явне оголошення забезпечує більшу гнучкість та ясність:

use App\Policies\InventoryPolicy;
use Illuminate\Database\Eloquent\Model;
use Laravel\Framework\Auth\Access\UsePolicy;

#[UsePolicy(InventoryPolicy::class)]
class Product extends Model
{
    protected $fillable = ['name', 'sku', 'category', 'price'];
}

Цей атрибут усуває неоднозначність щодо того, яка політика регулює перевірки авторизації, роблячи зв’язок явним, а не покладаючись на схеми іменування

Уявіть собі платформу електронної комерції, де елементи інвентарю потребують спеціалізованої авторизації в залежності від категорії та зв'язків з постачальниками. Різні типи продуктів можуть вимагати особливих правил безпеки, які виходять за межі стандартних операцій CRUD:

<?php

namespace App\Models;

use App\Policies\SupplierContentPolicy;
use Illuminate\Database\Eloquent\Model;
use Laravel\Framework\Auth\Access\UsePolicy;

#[UsePolicy(SupplierContentPolicy::class)]
class Product extends Model
{
    protected $fillable = [
        'name', 'description', 'price', 'category', 'supplier_id'
    ];

    public function isRestrictedCategory(): bool
    {
        return in_array($this->category, [
            'pharmaceuticals', 'electronics', 'restricted_chemicals'
        ]);
    }
}

class SupplierContentPolicy
{
    public function view(User $user, Product $product): bool
    {
        if ($product->isRestrictedCategory()) {
            return $user->hasRole('verified_buyer') || $user->hasRole('admin');
        }

        return $product->status === 'active';
    }

    public function update(User $user, Product $product): bool
    {
        if ($product->isRestrictedCategory()) {
            return $user->hasRole('supplier_admin');
        }

        return $user->id === $product->supplier_id || $user->hasRole('inventory_manager');
    }

    public function delete(User $user, Product $product): bool
    {
        return $user->hasRole('supplier_admin') ||
               ($user->id === $product->supplier_id && !$product->isRestrictedCategory());
    }
}

class ProductController extends Controller
{
    public function update(Request $request, Product $product)
    {
        $this->authorize('update', $product);
        
        $product->update($request->validated());

        return redirect()->route('products.show', $product);
    }
}

Цей явний підхід є безцінним, коли працюєте зі спільними політиками в різних моделях, моделями з ідентичними іменами в різних просторах імен, або коли нові члени команди повинні швидко зрозуміти авторизаційні потоки. Атрибут також покращує автодоповнення IDE та можливості статичного аналізу, роблячи реалізації безпеки більш доступними та зручними для підтримки