Rollen en rechten

De gebruiker is een User entity

Als je inlogd in het systeem is de gebruiker User entity.

Veld roles in de database

Als je de stappen hebt doorlopen zoals hier beschreven heeft een gebruiker standaard in de database een veld genaamd roles. Die heeft standaard de waarde van een lege array []
Je kan deze ophalen door de ->getRoles() methode aan te roepen. Deze zal dan de array teruggeven met, in de basis, altijd een rol ROLE_USER

Standaard ROLE_USER

Bij de standaard installatie zoals we deze in de eerdere paragrafen hebben doorlopen heeft de gebruiker standaard altijd een ROLE_USER rol. Dit komt door het volgende stukje code in de src/Entity/User.php

public function getRoles(): array
{
    $roles = $this->roles;
    // guarantee every user at least has ROLE_USER
    $roles[] = 'ROLE_USER';

    return array_unique($roles);
}

Andere mogelijke rollen?

Je kan zelf naar hartelust rollen verzinnen in een systeem. Denk bijvoorbeeld aan een ziekenhuis, daar heb je diverse rollen:

  • Doktoren (ROLE_DOCTOR)
  • Patienten (ROLE_PATIENT)
  • Beheerders (ROLE_ADMIN)
  • Assistenten (ROLE_ASSISTANT)
  • Afdelingshoofd (ROLE_DEPARTMENTHEAD)
  • Gasten (zij hebben geen rol, want zijn niet ingelogd)
Een overzicht van rollen, let op dat rollen ALTIJD allemaal hoofdletters bevatten

En zo kunnen we nog wel even door gaan. In het systeem van Symfony kan een gebruiker ook meerdere rollen hebben. Iedereen die ingelogd is heeft sowieso de rol ROLE_USER vanuit bovenstaande code en daar kan dus een andere rol bijkomen. Uiteraard in een goede omgeving heb je als beheerder een pagina om de gebruikers van het systeem de mogelijkheid om een gebruiker een of meerdere rollen te geven.

Denk bijvoorbeeld aan een dokter. Deze heeft standaard al de rol ROLE_USER en zal ook de rol ROLE_DOCTOR krijgen waarmee hij in het systeem patienten kan inzien en diagnoses kan opschrijven.
In de database kan je in het veld dan de volgende code zetten in het veld van deze gebruiker: ["ROLE_DOCTOR"]. De gebruiker in het systeem heeft nu de rollen ROLE_USER en ROLE_DOCTOR

Stel dat deze dokter de hoofd van een afdeling wordt dan krijgt hij een derde rol, namelijk die van ROLE_DEPARTMENTHEAD. In de database kan je het veld van deze gebruiker dan veranderen door deze rol toe te voegen, het nieuwe veld heeft dan als waarde: ["ROLE_DOCTOR", "ROLE_DEPARTMENTHEAD"]

De gebruiker heeft beide rollen nodig, hij is immers nog dokter in het ziekenhuis en moet bij de patienten gegevens kunnen, maar als afdelingshoofd moet hij ook bij de personeelsbestanden kunnen.

Werken met rollen in Controler

In een controller heb je de functie $this->isGranted("ROLE") met deze ingebouwde functie kan je snel kijken of er een gebruiker is ingelogd en als dit zo is of de gebruiker de betreffende rol heeft. Als de gebruiker de rol niet heeft, of niet ingelogd is, geeft deze functie FALSE terug, heeft de gebruiker de betreffende rol, dan krijg je TRUE. Deze kan je op deze wijze in een controller gebruiken met een if statement.

#[Route('/', name: 'app_index')]
public function index(): Response
{
    if ($this->isGranted("ROLE_ADMIN") {
        //The user has the role ROLE_ADMIN
    } else {
        //User is no admin
    }
}
Voorbeeld van het werken met een user in een controller

Checken van user en rechten in TWIG-bestanden

In de TWIG bestanden heb je de functie is_granted("ROLE"). Op dezelfde wijze als in de Controller met $this->isGranted() kan je de is_granted("ROLE") ook in TWIG bestanden gebruiken.


<div class="row">
    {% if is_granted("ROLE_ADMIN") %}
        - Je bent een beheerder van ons systeem
    {% endif %}
</div>
Voorbeeld van controle op user met rechten in een TWIG bestand

Afschermen van routes

In een goede veilige applicatie werk je met routes op basis van logica, de routes passen bij hetgene wat je wilt doen. Een route kan uit een of meerdere slugs bestaan. (http://localhost:8000/patients/show/1 heeft 3 slug-onderdelen, patients, show en 1.

Om er voor te zorgen dat een dokter wel bij de informatie van alle patienten kan en een patient alleen zijn eigen profiel kan zien (/profile/show) kan je de hele slug van /patients/ beveiligen dat alleen de rollen van doktoren, assistenten erbij kunnen.

De security.yaml

Dit afschermen doe je in het bestand /config/packages/security.yaml. Als je dit bestand opent dan heb je op een gegeven moment een deel dat begint met access_control

//..
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
    access_control:
        # - { path: ^/admin, roles: ROLE_ADMIN}
        # - { path: ^/profile, roles: ROLE_USER }
Als je de # weg zou halen heb je twee beschermde onderdelen in de applicatie.
/admin/ en alles wat er na komt. Dit is alleen toegankelijk voor gebruikers met de rol ROLE_ADMIN
En een /profile/ onderdeel wat alleen toegankelijk is voor ingelogde gebruikers. (Alle gebruikers die ingelogd zijn hebben immers de rol ROLE_USER

Meerdere rollen op een onderdeel

Heb je een onderdeel wat, zoals in bovenstaand voorbeeld, voor meerdere rollen toegankelijk is, dan kan je van de naam ook een array maken:
- { path: ^/patients, roles: [ROLE_DOCTOR, ROLE_ASSISTANT] }

Afschermen van een functie/ method in een controller

Naast dat je hele stukken code kan afschermen kan je ook in een Controller een functie afschermen. Dit kan je doen door boven de #[ROUTE ..] een extra beveiligingsregel te plaatsen #[IsGranted('ROLE_USER')]

//In de use-space staat ook de volgende zin:
use Symfony\Component\Security\Http\Attribute\IsGranted;

//Verder op in de code
#[IsGranted('ROLE_USER')]
#[Route('/home', name: 'app_home')]
public function home() :Response
{
    return $this->render('home/index.html.twig');
}
Voorbeeld van het beschermen van 1 functie (method) in een Controller op een bepaalde rol

Bovenstaande code geeft alleen toegang tot ingelogde gebruikers. Als een gebruiker niet ingelogd is zal het systeem vragen om in te loggen, als een gebruiker geen toegang heeft komt er een access denied melding.

Er zijn meer mogelijkheden

Er zijn meer mogelijkheden om de toegang te controleren in de Controller, dit is de basis maar online als je zou zoeken kan je dus nog andere oplossingen tegenkomen.