Vous êtes sur la page 1sur 48

Symfony 5 : gestion d’utilisateurs

Achref El Mouelhi

Docteur de l’université d’Aix-Marseille


Chercheur en Programmation par contrainte (IA)
Ingénieur en Génie logiciel

elmouelhi.achref@gmail.com

H & H: Research and Training 1 / 34


Plan

1 Introduction
2 Création d’utilisateur
3 Préparation de l’authentification
4 Déconnexion
5 Contrôle d’accès
Dans security.yaml
Dans le contrôleur
Dans la vue
6 Utilisateur authentifié
Dans le contrôleur
Dans la vue
7 Rôles hiérarchiques

H & H: Research and Training 2 / 34


Introduction

Symfony

But de la sécurité

c

Interdire, à un utilisateur, l’accès à une ressource à laquelle il n’a pas
I
droit
ELH
U
L MO
f E
chre
c A

H & H: Research and Training 3 / 34


Introduction

Symfony

But de la sécurité

c

Interdire, à un utilisateur, l’accès à une ressource à laquelle il n’a pas
I
droit
ELH
U
L MO
f E
Deux étapes
chre
c A

Qui veut accéder à la ressource ?
A t-il le droit d’y accéder ?

H & H: Research and Training 3 / 34


Introduction

Symfony

Configuration de la sécurité

En utilisant des données statiques (en mémoire)


I c

E
En utilisant des données dynamiques (stock H
L dans une base de
ées
U
données)
L MO
h r e fE
A c
c

H & H: Research and Training 4 / 34


Introduction

Symfony

Configuration de la sécurité

c

En utilisant des données statiques (en mémoire)
I
E
En utilisant des données dynamiques (stock H
L dans une base de
ées
U
données)
L MO
h r e fE
A c
Pour cela
c
On va utiliser un bundle Symfony à savoir security-bundle

H & H: Research and Training 4 / 34


Introduction

Symfony

Configuration de la sécurité
En utilisant les annotations I c

LH
Et en définissant quelques règles dansUE
config/packages/security.yml
L MO
e f E:
Mais on peut aussi rutiliser
h
c
le c AXML
format
les tableaux imbriqués de PHP

H & H: Research and Training 5 / 34


Introduction

Symfony

Contenu de security.yaml

security:
# https://symfony.com/doc/current/security.html#where-do-users-come
-from-user-providers
I c

providers:
ELH
users_in_memory: { memory: null }
U
MO
firewalls:
dev:

f E L
pattern: ˆ/(_(profiler|wdt)|css|images|js)/
security: false
chre
c A
main:


anonymous: lazy
provider: users_in_memory
access_control:
# - { path: ˆ/admin, roles: ROLE_ADMIN }
# - { path: ˆ/profile, roles: ROLE_USER }

H & H: Research and Training 6 / 34


Introduction

Symfony

Plusieurs étapes
I c
seL
Préparation de la partie utilisateur (qui va E
H
connecter)
O U
L M (formulaire
Préparation de la partie authentification
ref E
d’authentification, déconnexion...)
Gestioncde rA
c h
ôles

H & H: Research and Training 7 / 34


Introduction

Symfony

I c

H
EL du projet,
Si on n’a pas choisi la version complète à la création
exécutez O U
L M
h r e fE
composer require symfony/security-bundle

A c
c

H & H: Research and Training 8 / 34


Création d’utilisateur

Symfony
Pour créer la classe User

exécutez la commande php bin/console make:user

répondez à The name of the security user class par User

I c

répondez à Do you want to store user data in the database (via
Doctrine)? par yes
ELH
U
name for the user par email
L MO
répondez à Enter a property name that will be the unique "display"

f E
hre
répondez à Does this app need to hash/check user passwords? par yes
c
c A

H & H: Research and Training 9 / 34


Création d’utilisateur

Symfony
Pour créer la classe User

exécutez la commande php bin/console make:user

répondez à The name of the security user class par User

I c

répondez à Do you want to store user data in the database (via
Doctrine)? par yes
ELH
U
name for the user par email
L MO
répondez à Enter a property name that will be the unique "display"

f E
hre
répondez à Does this app need to hash/check user passwords? par yes
c
c A

Le résultat est
created: src/Entity/User.php
created: src/Repository/UserRepository.php
updated: src/Entity/User.php
updated: config/packages/security.yaml

H & H: Research and Training 9 / 34


Création d’utilisateur

Nouveau contenu de security.yaml

security:
encoders:
App\Entity\User:
algorithm: auto

# https://symfony.com/doc/current/security.html#where-do-users-come
-from-user-providers
I c

providers:

ELH
# used to reload user from session & other features (e.g.
switch_user)
U
app_user_provider:
L MO
entity:
f E
hre
class: App\Entity\User

c
property: email

c A
firewalls:
dev:

pattern: ˆ/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: lazy
provider: app_user_provider

access_control:

H & H: Research and Training 10 / 34


Création d’utilisateur

Symfony

Pour créer la table User

exécutez la commande php bin/console make:migration

I c

et ensuite la commande php bin/console doctrine:migrations:migrate

ELH
U
L MO
f E
chre
c A

H & H: Research and Training 11 / 34


Création d’utilisateur

Symfony

Pour créer la table User

exécutez la commande php bin/console make:migration

I c

et ensuite la commande php bin/console doctrine:migrations:migrate

ELH
U
L MO
f E
hre
Pour remplir la table User avec des données aléatoires
c
c A

installez le bundle de fixture composer require --dev
doctrine/doctrine-fixtures-bundle

demandez à ce bundle de remplir la table php bin/console make:fixtures

répondez à The class name of the fixtures to create par UserFixtures

H & H: Research and Training 11 / 34


Création d’utilisateur

Symfony
Contenu généré pour UserFixtures

namespace App\DataFixtures;

use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
I c

EL H
U
MO
class UserFixtures extends Fixture
{

fE L
h r e
public function load(ObjectManager
c
$manager)
{
// c
A = new Product();
$product
// $manager->persist($product);

$manager->flush();
}
}

H & H: Research and Training 12 / 34


Création d’utilisateur
Nouveau contenu de UserFixtures

class UserFixtures extends Fixture


{
private $passwordEncoder;

public function __construct(UserPasswordEncoderInterface $passwordEncoder)


{
$this->passwordEncoder = $passwordEncoder;
}
public function load(ObjectManager $manager)
{

I c

H
$user = new User();

EL
$user->setEmail(’wick@wick.us’);
$user->setRoles([’ROLE_ADMIN’]);

U
MO
$user->setPassword($this->passwordEncoder->encodePassword(
$user,

));
’wick’

f E L
hre
$manager->persist($user);
$user2 = new User();

c
c A
$user2->setEmail(’john@john.us’);
$user2->setPassword($this->passwordEncoder->encodePassword(

));

$user2,
’john’

$manager->persist($user2);
$manager->flush();
}
}

H & H: Research and Training 13 / 34


Création d’utilisateur
Nouveau contenu de UserFixtures

class UserFixtures extends Fixture


{
private $passwordEncoder;

public function __construct(UserPasswordEncoderInterface $passwordEncoder)


{
$this->passwordEncoder = $passwordEncoder;
}
public function load(ObjectManager $manager)
{

I c

H
$user = new User();

EL
$user->setEmail(’wick@wick.us’);
$user->setRoles([’ROLE_ADMIN’]);

U
MO
$user->setPassword($this->passwordEncoder->encodePassword(
$user,

));
’wick’

f E L
hre
$manager->persist($user);
$user2 = new User();

c
c A
$user2->setEmail(’john@john.us’);
$user2->setPassword($this->passwordEncoder->encodePassword(

));

$user2,
’john’

$manager->persist($user2);
$manager->flush();
}
}

Les use nécessaires

use App\Entity\User;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

H & H: Research and Training 13 / 34


Création d’utilisateur

Symfony

I c
H
ELexécutez
Pour insérer l’utilisateur dans la base de données,
O U
php bin/console doctrine:fixtures:load
L M ou php
bin/console d:f:l
h r e fE
A c
c

H & H: Research and Training 14 / 34


Préparation de l’authentification

À partir du terminal, exécutez la commande suivante


php bin/console make:auth

What style of authentication do you want? [Empty authenticator]:


[0] Empty authenticator
[1] Login form authenticator
> 1

The class name of the authenticator to create (e.g.


I c

AppCustomAuthenticator):
ELH
> LoginFormAuthenticator
U
L
Choose a name for the controller class (e.g. SecurityController) [ MO
f E
hre
SecurityController]:
> SecurityController
c
c A

Do you want to generate a ’/logout’ URL? (yes/no) [yes]:
> yes

H & H: Research and Training 15 / 34


Préparation de l’authentification

À partir du terminal, exécutez la commande suivante


php bin/console make:auth

What style of authentication do you want? [Empty authenticator]:


[0] Empty authenticator
[1] Login form authenticator
> 1

The class name of the authenticator to create (e.g.


I c

AppCustomAuthenticator):
ELH
> LoginFormAuthenticator
U
L
Choose a name for the controller class (e.g. SecurityController) [ MO
f E
hre
SecurityController]:
> SecurityController
c
c A

Do you want to generate a ’/logout’ URL? (yes/no) [yes]:
> yes

Le résultat est
created: src/Security/LoginFormAuthenticator.php
updated: config/packages/security.yaml
created: src/Controller/SecurityController.php
created: templates/security/login.html.twig
H & H: Research and Training 15 / 34
Préparation de l’authentification

Symfony

Pour tester, allez sur la route /login


essayez de vous connecter avec un email inexistant
I c

H
ensuite essayez de vous connecter avec un email existant et un
EL
mot de passe incorrect U
L MO et wick
h r e fE
enfin connectez-vous avec wick@wick.us

A c
c

H & H: Research and Training 16 / 34


Préparation de l’authentification

Symfony

Pour tester, allez sur la route /login


essayez de vous connecter avec un email inexistant
I c

H
ensuite essayez de vous connecter avec un email existant et un
EL
mot de passe incorrect U
L MO et wick
h r e fE
enfin connectez-vous avec wick@wick.us

A c
c

Remarque

Problème de redirection après la connexion

H & H: Research and Training 16 / 34


Préparation de l’authentification

Symfony
Pour résoudre ce problème, il faut modifier la méthode
onAuthenticationSuccess définie dans
security/LoginFormAuthenticator pour rediriger vers la
route home route
I c

public function onAuthenticationSuccess(Request
ELH
$request, TokenInterface $token, $providerKey)
U
{
L MO
f E
if ($targetPath = $this->getTargetPath($request
c hre
->getSession(), $providerKey)) {

}
c A

return new RedirectResponse($targetPath);

return new RedirectResponse($this->urlGenerator


->generate(’home_route’));
}

H & H: Research and Training 17 / 34


Préparation de l’authentification

Symfony
Pour modifier les messages d’erreurs de la page d’accueil, créez un fichier
security.en.xlf dans translations avec le contenu suivant
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1
.2">
<file source-language="en" datatype="plaintext" original="
I c

file.ext">
ELH
U
MO
<body>
<trans-unit id="Invalid credentials.">

f E L
<source>Invalid credentials.</source>

hre
<target>Le mot de passe est invalide</target>
c
c A
</trans-unit>

<trans-unit id="Email could not be found.">
<source>Email could not be found.</source>
<target>Email non-trouvé</target>
</trans-unit>
</body>
</file>
</xliff>

H & H: Research and Training 18 / 34


Déconnexion

Symfony

Pour se déconnecter
I c

essayez la route /logout
ELH
U
L MO
f E
chre
c A

H & H: Research and Training 19 / 34


Déconnexion

Symfony

Pour se déconnecter
I c

essayez la route /logout
ELH
U
L MO
f E
Question
A c hre
c
vers la page d’authentification ?
Comment rediriger

H & H: Research and Training 19 / 34


Déconnexion

Symfony

Allez à la section logout de security.yaml


logout:
path: app_logout
I c

# where to redirect after logout
ELH
# target: app_any_route
U
L MO
f E
chre
c A

H & H: Research and Training 20 / 34


Déconnexion

Symfony

Allez à la section logout de security.yaml


logout:
path: app_logout
I c

# where to redirect after logout
ELH
# target: app_any_route
U
L MO
f E
re et ajoutez la route
c
Décommentez la cléh
target
logout: c A
path: app_logout
# where to redirect after logout
target: app_login

H & H: Research and Training 20 / 34


Contrôle d’accès

Symfony

I c
Pour interdire l’accès à une page : deux solutions possibles
H
EL dans
soit en configurant la section access control
U
security.yaml
L MO
soit dans le contrôleur f E
c h re
c A
soit en utilisant la fonction is granted() dans la vue

H & H: Research and Training 21 / 34


Contrôle d’accès Dans security.yaml

Symfony

Pour interdire l’accès à tout utilisateur non-authentifié

access_control:
I c

- { path: ’ˆ/*’, roles: [IS_AUTHENTICATED_FULLY] }
ELH
- { path: ’ˆ/login’, roles: IS_AUTHENTICATED_ANONYMOUSLY }

U
L MO
f E
chre
c A

H & H: Research and Training 22 / 34


Contrôle d’accès Dans security.yaml

Symfony

Pour interdire l’accès à tout utilisateur non-authentifié

access_control:
I c

- { path: ’ˆ/*’, roles: [IS_AUTHENTICATED_FULLY] }
ELH
- { path: ’ˆ/login’, roles: IS_AUTHENTICATED_ANONYMOUSLY }

U
L MO
f E
hre
Pour autoriser les utilisateurs qui ont le rôle admin (ROLE ADMIN)
c
access_control:
c A

- { path: ’ˆ/login’, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ’ˆ/*’, roles: [ROLE_ADMIN] }

H & H: Research and Training 22 / 34


Contrôle d’accès Dans security.yaml

Symfony

Remarques
I c
L
La clé path accepte les expressions régulières
E H
U
MO
Le nom d’un rôle doit être écrit en majuscule
L
e
Les mots composants le
r E d’un rôle doivent être séparés par
f nom
un underscore.c h
c A
La clé roles accepte une valeur ou un tableau de valeurs

H & H: Research and Training 23 / 34


Contrôle d’accès Dans security.yaml

Symfony

Pour restreindre l’accès aux routes du contrôleur PersonneController aux


utilisateurs ayant le rôle ROLE ADMIN ou ROLE USER

access_control:
I c

EL
- { path: ’ˆ/personne’, roles: [ROLE_USER, ROLE_ADMIN] } H
U
L MO
f E
chre
c A

H & H: Research and Training 24 / 34


Contrôle d’accès Dans security.yaml

Symfony

Pour restreindre l’accès aux routes du contrôleur PersonneController aux


utilisateurs ayant le rôle ROLE ADMIN ou ROLE USER

access_control:
I c

ELH
- { path: ’ˆ/personne’, roles: [ROLE_USER, ROLE_ADMIN] }

U
L MO
f E
resuivant est affiché
c h
En testant, le message d’erreur
A one Security attribute to "Symfony\Component
Passing more c than
\Security\Core\Authorization\AccessDecisionManager::decide()"
is not supported.

H & H: Research and Training 24 / 34


Contrôle d’accès Dans security.yaml

Symfony

Explication

Bug dans la version 5 de Symfony


I c
EL H
U
Pour le corriger, il faut aller dans vendor\symfony\security-core
MO
\Authorization\TraceableAccessDecisionManager.php
L
e
Cherchez la méthoderdecide
h fE
A c
c
Faites les modifications indiquées dans la slide suivante ou dans
https://github.com/symfony/symfony/
commit/63984b013c92f5cd2373d81c19554b4270c4b776

H & H: Research and Training 25 / 34


Contrôle d’accès Dans security.yaml

Symfony
Remplacez
public function decide(TokenInterface $token, array $attributes,
$object = null): bool

I c

ELH
U
L MO
f E
chre
c A

H & H: Research and Training 26 / 34


Contrôle d’accès Dans security.yaml

Symfony
Remplacez
public function decide(TokenInterface $token, array $attributes,
$object = null): bool

Par
I c

ELH
U
public function decide(TokenInterface $token, array $attributes,

MO
$object = null/*, bool $allowMultipleAttributes = false*/): bool

f E L
chre
c A

H & H: Research and Training 26 / 34


Contrôle d’accès Dans security.yaml

Symfony
Remplacez
public function decide(TokenInterface $token, array $attributes,
$object = null): bool

Par
I c

ELH
U
public function decide(TokenInterface $token, array $attributes,

MO
$object = null/*, bool $allowMultipleAttributes = false*/): bool

f E L
chre
c A
Et


$result = $this->manager->decide($token, $attributes, $object);

H & H: Research and Training 26 / 34


Contrôle d’accès Dans security.yaml

Symfony
Remplacez
public function decide(TokenInterface $token, array $attributes,
$object = null): bool

Par
I c

ELH
U
public function decide(TokenInterface $token, array $attributes,

MO
$object = null/*, bool $allowMultipleAttributes = false*/): bool

f E L
chre
c A
Et


$result = $this->manager->decide($token, $attributes, $object);

Par
$result = $this->manager->decide($token, $attributes, $object, 3 < \
func_num_args() && func_get_arg(3));

H & H: Research and Training 26 / 34


Contrôle d’accès Dans le contrôleur

Symfony

Pour restreindre l’accès à une méthode de PersonneController


aux utilisateurs authentifiés
class PersonneController extends AbstractController
{
I c

/**
ELH
U
MO
* @Route("/personne/add", name="personne_add")
*/
f E L
hre
public function addForm(EntityManagerInterface
c
c A
$entityManager, Request $request)
{
$this->denyAccessUnlessGranted(’
IS_AUTHENTICATED_FULLY’);
// le reste du contenu
}

H & H: Research and Training 27 / 34


Contrôle d’accès Dans le contrôleur

Symfony

Pour restreindre l’accès à toutes les méthodes de


PersonneController aux utilisateurs ayant le rôle ROLE ADMIN
I c

/**
ELH
* U
* @IsGranted("ROLE_ADMIN")
L MO
*/ f E
chre
class PersonneController extends AbstractController
{
// le contenu
c A

}

H & H: Research and Training 28 / 34


Contrôle d’accès Dans le contrôleur

Symfony

Pour restreindre l’accès à une méthode de PersonneController


aux utilisateurs ayant le rôle ROLE ADMIN
class PersonneController extends AbstractController
I c

{
/** ELH
U
* @IsGranted("ROLE_ADMIN")
L MO
E
* @Route("/personne/add", name="personne_add")
f
*/
chre
c A
public function addForm(EntityManagerInterface

$entityManager, Request $request)
{
// le reste du contenu
}

H & H: Research and Training 29 / 34


Contrôle d’accès Dans la vue

Symfony

Pour restreindre une partie de la vue aux utilisateurs ayant le rôle


I c

ROLE ADMIN (contenu à ajouter dans home/index.html.twig)
EL H
U
{% if is_granted(’ROLE_ADMIN’) %}

L MO
<a href="{{ url(’personne_add’) }}">

</a> chre
f Epersonne
Ajouter une

%} A
{% endif c

H & H: Research and Training 30 / 34


Utilisateur authentifié Dans le contrôleur

Symfony
Pour récupérer l’utilisateur authentifié dans une méthode de
contrôleur
class PersonneController extends AbstractController
{
I c

/**
ELH
* @Route("/personne/add", name="personne_add") U
*/
L MO
f E
public function addForm(EntityManagerInterface
chre
$entityManager, Request $request)
{
c A

$this->denyAccessUnlessGranted(’
IS_AUTHENTICATED_FULLY’);
$user = $this->getUser();
// le reste du contenu
}

H & H: Research and Training 31 / 34


Utilisateur authentifié Dans le contrôleur

Symfony
Pour récupérer les rôles de l’utilisateur
class PersonneController extends AbstractController
{
/**
I c

* @Route("/personne/add", name="personne_add")
ELH
*/ U
public function addForm(EntityManagerInterface
L MO
f E
$entityManager, Request $request)
{
chre
c A

$this->denyAccessUnlessGranted(’
IS_AUTHENTICATED_FULLY’);
$user = $this->getUser();
roles = $user->getRoles();
// le reste du contenu
}

H & H: Research and Training 32 / 34


Utilisateur authentifié Dans la vue

Symfony

I c

Pour récupérer l’email de la personne authentifié (contenu à
EL
ajouter dans personne/index.html.twig)H
O%}U
M
{% if is_granted(’ROLE_ADMIN’)
L
r e f E
<p>Email: {{ app.user.email }}</p>
{% endif %}
A ch
c

H & H: Research and Training 33 / 34


Rôles hiérarchiques

Symfony

Dans security.yaml

security:
# ...

I c

role_hierarchy:
ROLE_ADMIN: ROLE_USER
ELH
U
MO
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

f E L
chre
Remarques c A

L’utilisateur ayant le rôle ROLE ADMIN a aussi le rôle ROLE USER

L’utilisateur ayant le rôle ROLE SUPER ADMIN a aussi les rôle ROLE ADMIN,
ROLE USER et ROLE ALLOWED TO SWITCH

H & H: Research and Training 34 / 34

Vous aimerez peut-être aussi