fbpx

Symfony Voter

Symfony Voter

Uprawnienia nigdy nie były prostym tematem. Zwykle zostawia się je na koniec projektu, co jest dużym błędem, ponieważ są ogromnie ważne i nigdy w swoich projektach nie traktuj ich po macoszemu. Dzisiejszy post jest pierwszym, ale na pewno nie ostatnim, w którym będę chciała pokazać Ci, jak ważny jest temat uprawnień oraz pokażę Ci jak je zrealizować w Symfony. Nie przeciągając, pierwszym narzędziem będzie w Symfony Voter.

Uprawnienia często kojarzą się z nudną robotą. Nie ukrywam, najciekawszym zajęciem nie są, to prawda. Jednak nie unikniemy ich, a nawet nie powinniśmy ich unikać więc do roboty!

Czym jest Voter

Voter jest serwisem, który jest odpowiedzialny za weryfikację dostępu np. do akcji, lub ogólniej zasobu. Wywoływany jest za każdym razem, gdy użyjemy metody isGranted(). Wielką zaletą votera jest to, że z racji tego, iż jest serwisem, możemy wstrzyknąć w niego np. repozytorium i zweryfikować dostęp w zależności od danych. Przyda się praktycznie we wszystkich przypadkach, gdzie sprawdzenie roli nie wystarcza.

Przykład Symfony Voter

Aby stworzyć Voter, potrzebujemy jednej klasy, u mnie AuthorVoter.php, która będzie dziedziczyć po klasie Voter. Posiada ona dwie najważniejsze i wymagane metody: supports i voteOnAttribute. Supports określa, na jakie typy akcji będą weryfikowane. W moim przypadku będzie to jedynie edycja, ale może to być także podgląd (view), jeśli tego potrzebujemy. Weryfikujemy także subject, czyli główny obiekt, który jest nam potrzebny do podjęcia decyzji.

Druga metoda — voteOnAttribute zawiera już samo mięso, czyli logikę Twojego votera. Zaczynam od pobrania zalogowanego użytkownika, jeśli nie jest zalogowany, to od razu zostaje zablokowany. Subject to ten konkretny post, który chcemy edytować. W dodatkowej metodzie isEdit() porównuję zalogowanego użytkownika do właściciela postu. Wynik tego porównania zwracam w metodzie głównej. To, co zwraca metoda voteOnAttribute, jest decyzją czy takiego użytkownika dopuszczamy do zasobu, czy nie.

<?php

namespace Backend\ProposalBundle\Voter;

use Symfony\Component\Security\Core\Authorization\Voter\Voter;

class AuthorVoter extends Voter
{    
    const EDIT = 'edit';
    
    protected function supports($attribute, $subject)
    {
        if (!in_array($attribute, [self::EDIT])) {
            return false;
        }

        if (!$subject instanceof Post) {
            return false;
        }

        return true;
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            return false;
        }
        
        $post = $subject;

        return $this->canEdit($post, $user);
    }

    private function canEdit(Post $post, User $user)
    {
        return $user === $post->getOwner();
    }
}

Teraz potrzebujemy podpiąć w symfony voter do systemu. Aby to zrobić, należy zdefiniować go jako serwis w DI. Bardzo ważne jest, aby taki serwis otagować.

services:
    author_voter:
        class: CoreBundle\Security\Voter
        tags:
            - { name: security.voter }

Aby zweryfikować, czy zalogowany autor może zmienić zawartość posta, wystarczy teraz w akcji edit wywołam metodę tak jak w poniższym przykładzie:

if (!$this->isGranted(AuthorVoter::EDIT, $post)) {
    return false;
}

Votery mogą się także opierać na roli, ale to równie obszerny temat, o którym wspomnę w następnym poście.

Zastosowanie

Teorię już znasz, zobaczyłeś przykładowy kod, teraz czas przeczytać, po co Ci w ogóle. Voter jest w stanie uzupełnić większość sytuacji, gdzie logika dostępu jest bardziej skomplikowana. W przypadkach, gdy sprawdzenie roli to za mało.

  1. Weryfikacja dostępu na podstawie relacji np. edytować artykuł może tylko jego autor.
  2. Weryfikacja dostępu np. do jego plików do pobrania.
  3. Sprawdzenie, czy dany użytkownik występuje w charakterze np. aktywnego użytkownika i w zależności od aktywności udostępnianie różnych menu.
  4. Sprawdzenie, czy występuje na pewnym poziomie struktury użytkowników, czy nie jest zbyt nisko w hierarchii np. nauczyciel-rodzic-dziecko.

Więcej info znajdziesz oczywiście w dokumentacji Symfony. Gdybyś miał jakieś pytania, to pisz śmiało!

Zgarnij darmowy ebook i cotygodniową dawkę wiedzy

.
Tags:
Magdalena Limanówka-Kuciel
magdalena@panizkomputerem.pl

Jestem programistką, która lubi mieć ręce pełne roboty. Do życia potrzebuje komputera z internetem i kubka gorącej kawy. Więcej na stronie o mnie.