Erweitertes Ressourcenautorisierungssystem in Laravel. Teil 3. Attribute lesen / schreiben, eigene Modelle

Einführung


Hallo, liebe Khabrovchans.

Heute mache ich Sie auf den letzten Teil einer Reihe von Artikeln zur erweiterten Autorisierung von Aktionen mit Ressourcen in Laravel aufmerksam. Um besser zu verstehen, was in diesem Artikel behandelt wird, müssen Sie den ersten und zweiten Teil lesen .


Diesmal hat sich die Problemstellung etwas geändert: Wir haben bereits die Autorisierung von Aktionen mit Ressourcen durch Autorisierung von Methoden der entsprechenden Controller. Die Aufgabe besteht darin, die Änderung / Anzeige bestimmter Felder des Modells zu autorisieren. Sie müssen auch die Möglichkeit erkennen, die Bearbeitung / Anzeige durch den Autor Ihrer Modelle zu autorisieren.


Dieses Material ist für praktizierende Programmierer gedacht und für unerfahrene Entwickler schwer zu verstehen.



Teil 4. Autorisierung von Aktionen mit Attributen


Theoretischer Teil


Laravel HasAttributes, HidesAttributes, GuardsAttributes. . / , / — .


:


  • getHidden(), getVisible() .
  • isFillable() .
  • authUpdate() .
  • authView() .
  • totallyGuarded() .

— , , . . , . - Banana Monkey Jungle, . / — . .


Laravel :


  • $visible
  • $hidden
  • $guarded
  • $fillable

. $visible . — $guarded . — , .



// , . app/Extensions/Traits, app/Extensions/Traits/GuardedModel. , ( ).

authView()( ) authUpdate()( ), , .

getVisible() getHidden().

, . filterVisibility(), , () .

filterVisibility() $hidden makeHidden(), , userCanViewAttribute($key) . makeVisible()


isFillable($key), , userCanUpdateAttribute($key)


userCanUpdateAttribute($key) userCanViewAttribute($key) . $user->can() spatie/laravel-permission. , , .


GuardedModel


<?php

namespace App\Extensions\Traits;

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

trait GuardedModel
{
    protected function authView(): array
    {
        return [];
    }

    protected function authUpdate(): array
    {
        return [];
    }

    public function getHidden(): array
    {
        $this->filterVisibility();

        return parent::getHidden();
    }

    public function getVisible(): array
    {
        $this->filterVisibility();

        return parent::getVisible();
    }

    public function isFillable($key)
    {
        if (in_array($key, $this->authView())) {
            return $this->userCanUpdateAttribute($key);
        }

        return parent::isFillable($key);
    }

    private function filterVisibility(): void
    {
        $this->makeHidden($this->authView());

        $authVisible = array_filter(
            $this->authView(),
            fn ($attr) => $this->userCanViewAttribute($attr)
        );

        $this->makeVisible($authVisible);
    }

    private function userCanViewAttribute(string $key): bool
    {
        /** @var User $user */
        $user = auth()->user();
        $ability = !empty($user) && $user->can("view-attr-$key-" . static::class);

        return $ability;
    }

    private function userCanUpdateAttribute(string $key): bool
    {
        /** @var User $user */
        $user = auth()->user();
        $ability = !empty($user) && $user->can("update-attr-$key-" . static::class);

        return $ability;
    }

    public function totallyGuarded()
    {
        $guarded = (
            count($this->getFillable()) === 0
            && count($this->authView()) === 0
            && $this->getGuarded() == ['*']
        );

        return  $guarded;
    }
}

totallyGuarded(). Illuminate\Database\Eloquent\MassAssignmentException , . — , .

$user->can(«update-attr-$key-». static::class), . , attr. /.


, authView() authUpdate(). user user_id. user_id, user user_id . . , , $guarded, $hidden, $fillable, .


Posts


<?php

namespace App\Models;

use App\Extensions\Traits\GuardedModel;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use GuardedModel;

    protected $hidden = ['id'];

    protected $guarded = ['created_at', 'updated_at'];

    protected $fillable = ['title', 'description', 'user_id'];

    protected function authView(): array
    {
        return ['user_id', 'user'];
    }

    protected function authUpdate(): array
    {
        return ['user_id'];
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

5.



. user(), user_id. . , . $user->can('delete-self-'. $this->getModelClass()). , . isOwner(User $user, Model $model). . , , — .


Allgemeine ModelPolicy- Richtlinie


<?php

namespace App\Policies;

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

abstract class ModelPolicy
{
    use HandlesAuthorization;

    abstract protected function getModelClass(): string;

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

        if ($user->can('delete-self-' . $this->getModelClass())) {
            return $this->isOwner($user, $model);
        }

        return false;
    }

    private function isOwner(User $user, Model $model): bool
    {
        if (!empty($user) && method_exists($model, 'user')) {
            return $user->getKey() === $model->getRelation('user')->getKey();
        }

        return false;
    }
}

Ich beachte auch, dass es zur Vermeidung von Fehlern zur Laufzeit sinnvoll ist, eine Überprüfung der Verfügbarkeit der user () -Methode oder ähnlichem im Zielmodell einzuführen .


Das ist alles für jetzt. Hoffe, dieser Artikel war hilfreich. Wir haben ein ziemlich vollständiges und flexibles System zur Genehmigung von Maßnahmen. Wenn Sie Fragen haben, werde ich auf jeden Fall antworten. Natürlich sind auch konstruktive Kommentare oder Vorschläge willkommen. Wenn Sie möchten, können Sie die Implementierung dieses Schulungsprojekts im Repository genauer sehen .


All Articles