Vous êtes sur la page 1sur 26

18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Accueil > Cours > Construisez un site web à l’aide du framework Symfony 5 > Sécurisez l'accès de votre site web

Construisez un site web à l’aide du framework


Symfony 5

20 heures  Moyenne
Mis à jour le 08/07/2022

 

Sécurisez l'accès de votre site web

04:23

À présent, il est temps de découvrir comment la sécurité est gérée avec Symfony. C'est une étape
un peu technique mais très importante et cela va nous permettre d'avoir un espace membre non
seulement fonctionnel mais également sécurisé !

Dans ce chapitre :

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 1/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

nous commencerons par un peu de théorie sur la sécurité avec Symfony,


puis nous créerons un espace membre.

C'est parti !

L'authentification vs. l'autorisation


Le contrôle de la sécurité sous Symfony est très avancé mais également très simple. Pour cela
Symfony distingue :

l'authentification,
l'autorisation.

Prenons quelques minutes pour définir ces mécanismes, c'est important pour le reste du
chapitre.

L'authentification, c'est le procédé qui permet de déterminer qui est votre visiteur. Il y a deux cas
possibles :

le visiteur est anonyme car il ne s'est pas identifié,


le visiteur est membre de votre site car s'est identifié.

L'utilisateur peut s'identifier grâce à un formulaire ou un cookie.

Sous Symfony, c'est le firewall qui prend en charge l'authentification.

En français, firewall signifie pare-feu.

Régler les paramètres du firewall va vous permettre de sécuriser le site. En effet, vous pouvez
restreindre l'accès à certaines parties du site uniquement aux visiteurs qui sont membres.
Autrement dit, il faudra que le visiteur soit authentifié pour que le firewall l'autorise à passer.

L'autorisation intervient après l'authentification. Comme son nom l'indique, c'est la procédure
qui va accorder les droits d'accès à un contenu. Sous Symfony, c'est l'access control qui prend en
charge l'autorisation.

Prenons l'exemple de différentes catégories de membres. Tous les visiteurs authentifiés ont le
droit de poster des messages sur le forum mais uniquement les membres administrateurs ont
des droits de modération et peuvent les supprimer. C'est l'access control qui permet de faire cela.

Etudions quelques cas de figure


Pour nous assurer que vous distinguez bien authentification et autorisation, nous allons voir
ensemble quelques cas de figure tirés de la documentation officielle. Ils vont nous permettre
d'identifier chaque composants.

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 2/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Cas n°1 : Un utilisateur anonyme souhaite se rendre sur la page /foo . Cette page est
accessible sans identification.

Comme il n'est pas nécessaire d'avoir des droits spécifiques pour accéder à cette page, tous les
visiteurs vont y accéder après avoir passé le pare-feu.

Le schéma suivant montre les différentes étapes du mécanisme de sécurité et distingue la partie
"authentification" (le firewall) de la partie "autorisation ("access control") :

Mécanisme de sécurité pour une page qui ne requiert pas de droit.

1. Un visiteur anonyme souhaite afficher la page /foo .

2. La configuration du pare-feu a été réalisée pour que cette page soit accessible sans
identification. Le visiteur peut donc passer.
3. L'access control, ou contrôle d'accès, vérifie si la page /foo demande des droits
particuliers. Ce n'est pas le cas donc le visiteur passe.
4. La page /foo s'affiche pour le visiteur.

Cas n°2 : Un utilisateur anonyme souhaite se rendre sur la page admin/foo . Cette
page demande des droits d'accès particulier.

Cette fois, notre visiteur anonyme souhaite afficher la page /admin/foo . Mais l'accès à cette
page est limité aux utilisateurs qui on un rôle ROLE_ADMIN. L'accès lui est donc refusé :

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 3/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Mécanisme de sécurité pour une page qui requiert des droits particuliers
: visiteur anonyme.

1. Le visiteur anonyme souhaite afficher la page /admin/foo .


2. La configuration du pare-feu a été réalisée pour que cette page soit accessible sans
identification. Le visiteur peut donc passer.
3. Le contrôle d'accès vérifie si la page /admin/foo demande des droits particuliers. C'est le
cas : il est nécessaire d'avoir un rôle ROLE_ADMIN. Le contrôle d'accès interdit donc
l'affichage de la page /admin/foo à notre utilisateur.
4. Le visiteur est redirigé vers une page pour s'identifier.

Cas n°3 : Un utilisateur identifié souhaite se rendre sur la page admin/foo . Cette page
demande des droits d'accès particulier.

Notre visiteur n'est plus anonyme car il s'est identifié :

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 4/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Mécanisme de sécurité pour une page qui requiert des droits particuliers
: visiteur identifié.

1. Après l'étape d'identification, Brian souhaite afficher la page /admin/foo .


L'authentification est vérifiée par le firewall qui le laisse ensuite passer.
2. Ensuite, le contrôle d'accès vérifie les droits pour la page /admin/foo . Le rôle
ROLE_ADMIN est requis mais Brian n'en dispose pas. L'accès à /admin/foo lui est donc
interdit.
3. Cette fois, Brian est redirigé vers une page d'erreur par le contrôle d'accès, lui expliquant
qu'il ne dispose pas des droits requis.

Cas n°4 : Un utilisateur identifié souhaite se rendre sur la page admin/foo . L'utilisateur
dispose des droits d'accès requis.

Le visiteur, Mickaël, s'est identifié et a des droits d'administrateurs. Puisqu'il a le rôle


ROLE_ADMIN, il peut donc voir la page /admin/foo :

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 5/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Mécanisme de sécurité pour une page qui requiert des droits particuliers
: le visiteur a le rôle requis.

1. Après son identification, Mickaël souhaite afficher /admin/foo . L'authentification est


vérifiée par le firewall qui le laisse ensuite passer.
2. Le contrôle d'accès vérifie les droits pour la page /admin/foo . Le rôle ROLE_ADMIN est
requis et Mickaël en dispose bien. L'accès à /admin/foo est donc autorisé.
3. La page /admin/foo s'affiche puis le visiteur a été authentifié et qu'il a les droits requis.

Récapitulatif

Les étapes sont toujours les mêmes :

1. Un visiteur souhaite voir un contenu dont l'accès est limité.


2. Il est renvoyé vers un formulaire d'identification par le firewall. L'utilise s'identifie (en
utilisant un login et un mot de passe le plus souvent).
3. Le firewall l'authentifie en confirmant son identification.
4. Le requête de départ est renvoyée par le visiteur authentifié.
5. Les droits du visiteur sont vérifiés par le contrôle d'accès. L'affichage du contenu est
autorisé ou non selon ces droits.

Le processus de sécurité suit toujours ces étapes mais le nature de l'authentification peut
varier. En effet, selon vos besoins, il existe de nombreuses manières d'authentifier les
visiteurs, (banal formulaire d'identification, authentification avec Google, etc). Il faut retenir
que la méthode choisie n'a pas d'incidence sur votre code.

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 6/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Passons à la pratique


Même si le mécanisme de sécurité est plutôt simple à appréhender, cela prend quand même un
peu temps à mettre en place. Procédons par étape !

Configurez la sécurité
L'importance de la sécurité est telle qu'il y a un fichier de configuration dédié ! C'est le
fichier security.yaml qui se trouve dans le répertoire config/packages de votre application. Pour
l'instant, il n'y a pas grand chose dedans. Nous allons déjà y ajouter ces sections (elles sont
décrites ensuite) :
yaml

1 # config/packages/security.yaml
2
3 security:
4 encoders:
5 Symfony\Component\Security\Core\User\User: plaintext
6
7 role_hierarchy:
8 ROLE_ADMIN: ROLE_USER
9 ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
10
11 providers:
12 in_memory:
13 memory:
14 users:
15 user: { password: userpass, roles: [ 'ROLE_USER' ] }
16 admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
17
18 firewalls:
19 dev:
20 pattern: ^/(_(profiler|wdt)|css|images|js)/
21 security: false
22
23 access_control:
24 #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
25

La section de base se nomme security car c'est le nom que le bundle SecurityBundle
a retenu pour sa configuration. En effet, dans Symfony, la sécurité vient d'un bundle ! C'est
ce bundle que nous allons configurer.

Commençons par décortiquer chacune des sections de ce fichier de configuration.

Encoders
yaml

1 security:
2 encoders:
3 Symfony\Component\Security\Core\User\User: plaintext

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 7/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Comme son nom l'indique, l'objet encodeur va encoder les mots de passe des utilisateurs. C'est
donc grâce à cette section que vous pourrez changer d'encodeur, c'est-à-dire la manière dont les
mots de passe sont encodés dans votre application.

Ici, nous utilisons plaintext qui laisse les mots de passe apparents (donc il n'encode rien en
fait !). Nous choisirons un encodeur plus sûr plus tard.

Les mots de passe sont visibles par la suite grâce à l'encodeur plaintext .

role_hierarchy
yaml

1 security:
2 role_hierarchy:
3 ROLE_ADMIN: ROLE_USER
4 ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

Comme nous l'avons vu, le "rôle" de l'utilisateur est central pour l'autorisation. Il est possible de
définir différents rôles et d'en attribuer un ou plusieurs pour un utilisateur donné. De même,
l'accès à chaque ressource est conditionné par un ou plusieurs rôles. Le contrôle d'accès s'assure
que l'utilisateur a le rôle nécessaire puis autorise (ou non) l'accès.

La hiérarchie des différents rôles est établie dans cette section. Par exemple, le rôle ROLE_USER
est inclus dans le rôle ROLE_ADMIN. Concrètement, cela veut dire qu'un utilisateur qui a le rôle
ROLE_ADMIN peut accéder à des pages qui nécessite seulement le rôle ROLE_USER.

Vous pouvez nommer vos rôles comme vous le souhaitez, l'important est qu'ils commencent par «
ROLE_ ».

Providers
yaml

1 security:
2 providers:
3 in_memory:
4 memory:
5 users:
6 user: { password: userpass, roles: [ 'ROLE_USER' ] }
7 admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }

Pour identifier les utilisateurs, le firewall demande à un provider. C'est un fournisseur


d'utilisateurs.

Si vous regardez le fichier, pour l'instant il n'y qu'un fournisseur et c'est in_memory (vous pouvez
tout à fait choisir un autre nom). C'est un fournisseur atypique utilisé pour le développement. En
effet, les utilisateurs, ici user et admin, sont répertoriés dans le fichier de configuration. Ainsi, nous
n'avons pas besoin d'une base de données pour tester la sécurité de notre application.

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 8/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Passée la phase de test, il faudra utiliser un autre type de fournisseur (par exemple un
fournisseur permettant de recourir à une base de données).

Firewalls
yaml

1 security:
2 firewalls:
3 dev:
4 pattern: ^/(_(profiler|wdt)|css|images|js)/
5 security: false

Le firewall permet de vérifier l'identité de l'utilisateur. Dans notre cas, notre firewall est dev
(ceux de démonstration ont été retirés). Il désactive la sécurité pour certaines URL. Nous y
reviendrons.

access_control
yaml

1 security:
2 access_control:
3 #- { path: ^/login, roles: ROLE_ADMIN }

Le contrôle d'accès vérifie que l'utilisateur a le(s) rôle(s) requis pour accéder au contenu demandé.
Les contrôles d'accès peuvent être utilisés :

à partir du fichier de configuration, comme c'est le cas ici. Pour cela, il faut appliquer règles
sur des URL. Par exemple, on peut sécuriser toutes les URL commençant par /admin ;
dans les contrôleurs directement. Pour cela, il faut appliquer des règles sur les méthodes
des contrôleurs. L'avantage est la grande liberté que cela apporte : les règles peuvent
changer en fonction des paramètres.

Ces deux manières de faire sont complémentaires !

Créez un formulaire de connexion


Après cette présentation du fichier de configuration, vous devez mieux comprendre ce qui peut
être configuré. Passons à l'étape suivante : l'authentification !

Pour cela, nous allons mettre en place un formulaire qui demande à l'utilisateur son adresse mail
et un mot de passe.

Créez un formulaire
C'est le plus simple, il s'agit d'intégrer un simple formulaire HTML : faisons-le en Twig, par
exemple.
twig

1 {% extends 'base.html.twig' %}

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre-… 9/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

2
3 {% block main %}
4 {% if error %}
5 <div class="alert alert-danger">
6 {{ error.messageKey|trans(error.messageData, 'security') }}
7 </div>
8 {% endif %}
9
10 <div class="row">
11 <div class="col-sm-5">
12 <div class="well">
13 <form action="{{ path('security_login') }}" method="post">
14 <fieldset>
15 <legend><i class="fa fa-lock" aria-hidden="true"></i> {{
'title.login'|trans }}</legend>
16 <div class="form-group">
17 <label for="username">{{ 'label.username'|trans }}</label>
18 <input type="text" id="username" name="username" value="{{
last_username }}" class="form-control"/>
19 </div>
20 <div class="form-group">
21 <label for="password">{{ 'label.password'|trans }}</label>
22 <input type="password" id="password" name="password" class="form-
control" />
23 </div>
24 <input type="hidden" name="_target_path" value="{{
app.request.get('redirect_to') }}"/>
25 <input type="hidden" name="_csrf_token" value="{{
csrf_token('authenticate') }}"/>
26 <button type="submit" class="btn btn-primary">
27 <i class="fa fa-sign-in" aria-hidden="true"></i> {{
'action.sign_in'|trans }}
28 </button>
29 </fieldset>
30 </form>
31 </div>
32 </div>
33 </div>
34 {% endblock %}

Pour le rendu visuel correspondant dans le projet de démonstration de ce cours :

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 10/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Formulaire de connexion

Quelques contraintes sont à connaître :

le "login" doit avoir l'attribut name "username" ;


le "mot de passe" doit avoir l'attribut name "password".

Créez un contrôleur
Pour manipuler un formulaire de connexion, il nous faut un contrôleur ! Ce contrôleur aura deux
fonctions : une pour la connexion et une pour la déconnexion.
php

1 <?php
2
3 namespace App\Controller;
4
5 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
6 use Symfony\Component\HttpFoundation\Response;
7 use Symfony\Component\Routing\Annotation\Route;
8 use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
9
10 class SecurityController extends AbstractController
11 {
12 /**
13 * @Route("/login", name="security_login")
14 */
15 public function login(AuthenticationUtils $authenticationUtils): Response
16 {
17 // retrouver une erreur d'authentification s'il y en a une
18 $error = $authenticationUtils->getLastAuthenticationError();
19 // retrouver le dernier identifiant de connexion utilisé
20 $lastUsername = $authenticationUtils->getLastUsername();
21
22 return $this->render('security/login.html.twig', [
23 'last_username' => $lastUsername,
24 'error' => $error,
25 ]
26 );
27 }
28
29 /**
30 * @Route("/logout", name="security_logout")
31 */
32 public function logout(): void
33 {
34 throw new \Exception('This should never be reached!');
35 }
36 }
37

Quelques informations s'imposent. Tout d'abord, nous allons utiliser un


service AuthenticationUtils dans la fonction de connexion, dont la responsabilité est de valider

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 11/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

l'authentification.

La fonction de déconnexion doit vous surprendre ! Nous avons dit qu'une action doit toujours
retourner une réponse : en fait, cette fonction ne sera jamais exécutée. Le composant Sécurité a
seulement besoin d'une URL pour effectuer la déconnexion.

Il manque quelque chose pour faire le lien : la méthode d'authentification !

Créez de la méthode d'authentification


Pour créer une méthode d'authentification, nous allons utiliser une extension du composant
Security appelée Guard. Changement majeur par rapport aux anciennes versions de Symfony, il
est maintenant très facile de créer sa méthode d'authentification ou encore "authenticator".

Pour cela, nous allons créer une classe qui étend AbstractFormLoginAuthenticator du
composant Guard. Il faudra implémenter et compléter quelques fonctions :

supports() : la fonction définit dans quelles conditions la classe sera appelée.


getCredentials() : retourne les éléments d'information d'authentification.
getUser() : retourne un utilisateur au sens Symfony (instance de UserInterface du
composant Security).
checkCredentials() : contrôle à la connexion que les informations d'authentification sont
valides.
onAuthenticationSuccess() : décide que faire dans le cas où l'utilisateur est bien
authentifié, généralement une redirection vers une URL donnée.
getLoginUrl() : définit l’URL du formulaire de connexion, dans notre cas security_login .

Voici une implémentation valide :


php

1 <?php
2
3 namespace App\Security;
4
5 use App\Entity\User;
6 use Doctrine\ORM\EntityManagerInterface;
7 use Symfony\Component\HttpFoundation\RedirectResponse;
8 use Symfony\Component\HttpFoundation\Request;
9 use Symfony\Component\Routing\RouterInterface;
10 use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
11 use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
12 use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
13 use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
14 use Symfony\Component\Security\Core\Security;
15 use Symfony\Component\Security\Core\User\UserInterface;
16 use Symfony\Component\Security\Core\User\UserProviderInterface;
17 use Symfony\Component\Security\Csrf\CsrfToken;
18 use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
19 use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
20 use Symfony\Component\Security\Http\Util\TargetPathTrait;
21
https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 12/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

22 class FormLoginAuthenticator extends AbstractFormLoginAuthenticator


23 {
24 use TargetPathTrait;
25
26 private $entityManager;
27 private $router;
28 private $csrfTokenManager;
29 private $passwordEncoder;
30
31 public function __construct(EntityManagerInterface $entityManager, RouterInterface $router,
CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
32 {
33 $this->entityManager = $entityManager;
34 $this->router = $router;
35 $this->csrfTokenManager = $csrfTokenManager;
36 $this->passwordEncoder = $passwordEncoder;
37 }
38
39 public function supports(Request $request)
40 {
41 return 'security_login' === $request->attributes->get('_route')
42 && $request->isMethod('POST');
43 }
44
45 public function getCredentials(Request $request)
46 {
47 $credentials = [
48 'username' => $request->request->get('username'),
49 'password' => $request->request->get('password'),
50 'csrf_token' => $request->request->get('_csrf_token'),
51 ];
52 $request->getSession()->set(
53 Security::LAST_USERNAME,
54 $credentials['username']
55 );
56
57 return $credentials;
58 }
59
60 public function getUser($credentials, UserProviderInterface $userProvider)
61 {
62 $token = new CsrfToken('authenticate', $credentials['csrf_token']);
63 if (!$this->csrfTokenManager->isTokenValid($token)) {
64 throw new InvalidCsrfTokenException();
65 }
66
67 $user = $this->entityManager->getRepository(User::class)->findOneBy(['username' =>
$credentials['username']]);
68
69 if (!$user) {
70 // fail authentication with a custom error
71 throw new CustomUserMessageAuthenticationException('Username could not be found.');
72 }
73
74 return $user;
75 }
76
77 public function checkCredentials($credentials, UserInterface $user)
https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 13/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

78 {
79 return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
80 }
81
82 public function onAuthenticationSuccess(Request $request, TokenInterface $token,
$providerKey)
83 {
84 if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
85 return new RedirectResponse($targetPath);
86 }
87
88 return new RedirectResponse($this->router->generate('homepage'));
89 }
90
91 protected function getLoginUrl()
92 {
93 return $this->router->generate('security_login');
94 }
95 }

Une fois cette classe réalisée et correctement implémentée, passons à la création de notre classe
Utilisateur.

Création d'utilisateurs et persistance en base


Il ne vous aura pas échappé que le but du formulaire de connexion est de retrouver un utilisateur
à partir des informations soumises par l'utilisateur.

Une seule contrainte pour la création d'un utilisateur est d'implémenter l'interface UserInterface
du composant Security. Voici un exemple d'implémentation valide utilisé dans le projet de
démonstration :
php

1 <?php
2
3 namespace App\Entity;
4
5 use Doctrine\ORM\Mapping as ORM;
6 use Symfony\Component\Security\Core\User\UserInterface;
7 use Symfony\Component\Validator\Constraints as Assert;
8
9 /**
10 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
11 * @ORM\Table(name="blog_user")
12 *
13 */
14 class User implements UserInterface
15 {
16 /**
17 * @ORM\Id
18 * @ORM\GeneratedValue
19 * @ORM\Column(type="integer")
20 */
21 private $id;
22
23 /**
https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 14/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

24 * @ORM\Column(type="string")
25 * @Assert\NotBlank()
26 */
27 private $fullName;
28
29 /**
30 * @ORM\Column(type="string", unique=true)
31 * @Assert\NotBlank()
32 * @Assert\Length(min=2, max=50)
33 */
34 private $username;
35
36 /**
37 * @ORM\Column(type="string", unique=true)
38 * @Assert\Email()
39 */
40 private $email;
41
42 /**
43 * @ORM\Column(type="string")
44 */
45 private $password;
46
47 /**
48 * @ORM\Column(type="json")
49 */
50 private $roles = [];
51
52 public function getId(): int
53 {
54 return $this->id;
55 }
56
57 public function setFullName(string $fullName): void
58 {
59 $this->fullName = $fullName;
60 }
61
62 public function getFullName(): string
63 {
64 return $this->fullName;
65 }
66
67 public function getUsername(): string
68 {
69 return $this->username;
70 }
71
72 public function setUsername(string $username): void
73 {
74 $this->username = $username;
75 }
76
77 public function getEmail(): string
78 {
79 return $this->email;
80 }
81
https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 15/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

82 public function setEmail(string $email): void


83 {
84 $this->email = $email;
85 }
86
87 public function getPassword(): string
88 {
89 return $this->password;
90 }
91
92 public function setPassword(string $password): void
93 {
94 $this->password = $password;
95 }
96
97 public function getRoles(): array
98 {
99 $roles = $this->roles;
100
101 // il est obligatoire d'avoir au moins un rôle si on est authentifié, par convention
c'est ROLE_USER
102 if (empty($roles)) {
103 $roles[] = 'ROLE_USER';
104 }
105
106 return array_unique($roles);
107 }
108
109 public function setRoles(array $roles): void
110 {
111 $this->roles = $roles;
112 }
113
114 public function getSalt(): ?string
115 {
116 return null;
117 }
118
119 public function eraseCredentials(): void
120 {
121 }
122 }
123

Il n'est pas obligatoire d'utiliser Doctrine ORM pour persister ses utilisateurs, comme nous
l'avons vu dans la section providers du fichier security.yaml.

Configurez la méthode d'authentification


Il est temps de retourner dans le fichier security.yaml pour déclarer notre authenticator, d'une
part, et configurer le fournisseur d'utilisateur (le provider) pour utiliser Doctrine ORM, d'autre part.

Voici le fichier security.yaml mis à jour :


yaml

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 16/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

1 # config/security.yaml
2
3 security:
4 encoders:
5 App\Entity\User: bcrypt
6
7 providers:
8 database_users:
9 entity: { class: App\Entity\User, property: username }
10
11 firewalls:
12 dev:
13 pattern: ^/(_(profiler|wdt)|css|images|js)/
14 security: false
15
16 main:
17 pattern: ^/
18 anonymous: true
19 logout:
20 path: security_logout
21 guard:
22 authenticators:
23 - App\Security\FormLoginAuthenticator
24

Et après tant d'efforts, et après avoir créé un utilisateur en base de données, vous pouvez
maintenant vous connecter :

John est bien authentifié !

L'utilisateur John est donc authentifié et aura les rôles définis pour cet utilisateur, que ce soit en
base de données, en mémoire, ou toute autre méthode que vous pouvez définir en créant votre
propre "User Provider", ou encore fournisseur d'utilisateurs.

Je suis un peu gêné de vous dire cela maintenant : vous pouvez générer ce code assez
facilement en installant l'extension MakerBundle et à l'aide des commandes make:user
et make:auth .

Vous aurez un formulaire d'authentification fonctionnel en quelques minutes de travail

seulement !

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 17/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Récupérez son utilisateur


Une fois authentifié, on peut donc accéder à son utilisateur n'importe où dans nos applications,
que ce soit dans nos services, dans nos contrôleurs et dans nos vues.

Accédez à l'utilisateur dans vos contrôleurs


Dans les contrôleurs, une fois authentifié, il est possible d'accéder à l'utilisateur à l'aide de la
fonction getUser() :
php

1 <?php
2
3 class TestController extends AbstractController
4 {
5 public function index()
6 {
7 dump($this->getUser()->getUsername());
8 }
9 }

La fonction getUser() est disponible dans AbstractController et retourne soit nul, soit l'utilisateur
authentifié.

Si, pour une raison particulière, vous ne souhaitez pas utiliser cet alias, on peut injecter le service
Security dans l'action :
php

1 <?php
2
3 use Symfony\Component\Security\Core\Security;
4
5 class TestController extends AbstractController
6 {
7 public function index(Security $security)
8 {
9 dump($security->getUser());
10 }
11 }

Et vous pouvez réutiliser ce service pour retrouver l'utilisateur authentifié dans vos classes !

Accédez à l'utilisateur courant dans vos gabarits


Accéder à l'utilisateur courant dans vos gabarits Twig est très facile, à l'aide de la variable globale
app.

Voici un exemple d'utilisation pour vos gabarits :


twig

1 {{ app.user.username }}

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 18/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Avec toutes ces informations, vous devriez être capable de développer une page "Compte
utilisateur" sans aucun souci !

Créez un espace administrateur


Nous avons maintenant des utilisateurs qui peuvent s'authentifier et qui ont différents rôles.

L'idée d'un espace administrateur est de restreindre l'accès aux utilisateurs qui ont le rôle
ROLE_ADMIN .

Mise en place de l'accès privé


Une première solution est d'utiliser l'annotation @IsGranted() au niveau des contrôleurs
concernés par la partie /admin :
php

1 <?php
2
3 namespace App\Controller\Admin;
4
5 use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
6 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
7 use Symfony\Component\Routing\Annotation\Route;
8
9 /**
10 * Controller used to manage blog contents in the backend.
11 *
12 * @Route("/admin/post")
13 * @IsGranted("ROLE_ADMIN")
14 */
15 class BlogController extends AbstractController
16 {
17 // ...
18 }

L'annotation IsGranted attachée au niveau du contrôleur permet de vérifier que l'utilisateur


authentifié a bien le rôle ROLE_ADMIN ; sinon, une exception de type
AccessDeniedHttpException sera lancée.

Une deuxième solution est d'utiliser un concept que vous avez déjà vu dans la première partie de
ce chapitre : définir une règle de contrôle d'accès.

Mettons à jour le fichier security.yaml et ajoutons une règle dans la section access_control :
yaml

1 access_control:
2 - { path: '^/admin', roles: ROLE_ADMIN }

Si vous essayez d'accéder à l'espace administration sans être connecté, le site redirigera
vers la page de connexion.

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 19/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

Je vois parfois, dans des applications, l'annotation @Security(), pourquoi tu n'en parles pas
?

Cette annotation est dépréciée et ne sera plus disponible dans Symfony 5 ! L'annotation
@IsGranted() a les mêmes fonctionnalités, donc vous pouvez convertir tous les appels à
l'annotation @Security() par @IsGranted().

Contrôle des droits d'un utilisateur


Nous avons vu comment contrôler l'accès d'un utilisateur à un contrôleur, ou à une plage d'URL, à
l'aide du contrôle d'accès dans la configuration de la sécurité de nos applications.

On peut aussi affiner les différentes autorisations au niveau d'une action, d'un service ou même
d'un gabarit Twig.

Contrôle des autorisations dans un gabarit


Par exemple, imaginons que nous souhaitons afficher un lien d'édition d'un article du blog
seulement si l'utilisateur est administrateur :
twig

1 {% if is_granted('ROLE_ADMIN') %}
2 <div class="section">
3 <a href="{{ path('admin_post_edit', {id: post.id}) }}">
4 <i class="fa fa-edit" aria-hidden="true"></i> {{ 'action.edit_post'|trans }}
5 </a>
6 </div>
7 {% endif %}

Contrôle des autorisations dans un contrôleur


Nous avons vu comment utiliser l'annotation IsGranted(), car vous pourriez avoir envie de
contrôler l'accès à une action du contrôleur seulement si l'on rentre dans une condition
particulière de cette action. Puisque l'annotation est exécutée avant d'entrer dans l'action (dans la
fonction), on peut utiliser la fonction denyAccessUnlessGranted($role) :
php

1 <?php
2
3 use Symfony\Component\Security\Core\Security;
4
5 class ExempleController extends AbstractController
6 {
7 public function index()
8 {
9 //...
10 if ($someConditions) {
11 $this->denyAccessUnlessGranted('ROLE_SPECIFIC');
12 }
13 }
14
15 // en utilisant l'injection de dépendances

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 20/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

16 public function show(Security $security)


17 {
18 if ($someConditions) {
19 $security->isGranted('ROLE_SPECIFIC');
20 }
21 }
22 }

D'accord, c'est très clair... mais j'ai un besoin un peu particulier ! Je veux par exemple
permettre à un utilisateur d'éditer un article s'il est le créateur de son article. Je ne vais pas
créer un rôle à chaque fois, si ?

Mais non, ne vous inquiétez pas ! Le contrôle de la sécurité en fonction d'un rôle, c'est le premier
niveau de permission implémenté par le composant Security. Le second niveau, c'est le contrôle
d'une action propre à un objet. Je vous explique.

Mise en place de règles complexes


Reprenons l'exemple précédent avec les connaissances que vous avez déjà. Nous pourrions déjà
écrire le code suivant dans notre contrôleur :
php

1 <?php
2
3 use App\Entity\Article;
4 // ...
5
6 class ArticleController extends AbstractController
7 {
8 public function edit(Article $article)
9 {
10 if ($this->getUser() !== $article->getAuthor() || !$this->isGranted('ROLE_ADMIN')) {
11 throw $this->createAccessDeniedException();
12 }
13 }
14 }

Et ce code fonctionne parfaitement. Mais... nous avons de la logique business à réécrire dans le
contrôleur, dans les gabarits Twig, et si les règles changent ou si elles sont dynamiques, cela va
vite devenir compliqué à maintenir !

Pourtant la solution existe, regardez le code de ce contrôleur mis à jour :


php

1 <?php
2
3 use App\Entity\Article;
4 // ...
5
6 class ArticleController extends AbstractController
7 {
8 public function edit(Article $article)

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 21/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

9 {
10 if (!$this->isGranted('EDIT', $article)) {
11 throw $this->createAccessDeniedException();
12 }
13 }
14 }

Sérieux ? C'est tout ?

Pas tout à fait, nous allons devoir déplacer nos règles de décision métier dans une classe dédiée
appelée un Voteur.

Créez un Voteur pour implémenter des règles spécifiques


Un Voteur, c'est une classe dont la responsabilité est de voter si une action sur un objet est
autorisée.

Pour créer un Voteur, le plus simple est d'étendre la classe Voter du composant Security.

Il faudra implémenter deux fonctions principales :

supports($attribute, $subject) : définit si le Voteur doit voter ou non sur cette demande
d'autorisation ;
voteOnAttribute($attribute, $subject, $token): cette fonction doit retourner true ou
false ; c'est ici que l'on peut décrire les conditions métiers qui conditionnent
l'autorisation.

Voici comment nous pourrions utiliser un Voter pour implémenter notre besoin :
php

1 <?php
2
3 namespace App\Security\Voter;
4
5 use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
6 use Symfony\Component\Security\Core\Authorization\Voter\Voter;
7 use Symfony\Component\Security\Core\User\UserInterface;
8 use Symfony\Component\Security\Core\Security;
9
10 class ArticleEditionVoter extends Voter
11 {
12 private $security;
13
14 public function __construct(Security $security)
15 {
16 $this->security = $security;
17 }
18
19 protected function supports($attribute, $subject)
20 {
21 return $attribute === 'EDIT'
22 && $subject instanceof App\Entity\Article;
https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 22/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

23 }
24
25 protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
26 {
27 // on retrouve l'utilisateur (on peut aussi ré-utiliser $this->security)
28 $user = $token->getUser();
29
30 // si l'utilisateur n'est pas authentifié, c'est non!
31 if (!$user instanceof UserInterface) {
32 return false;
33 }
34
35 // l'utilisateur est l'auteur de l'article
36 if ($user === $subject->getAuthor()) {
37 return true;
38 }
39
40 // l'utilisateur est un administrateur
41 if ($this->security->isGranted('ROLE_ADMIN')) {
42 return true;
43 }
44
45 return false;
46 }
47 }
48

Avec l'extension MakerBundle, vous pouvez créer un Voter à l'aide de la commande


make:voter.

Dans ce Voteur, j'ai eu besoin de vérifier que l'utilisateur avait bien le rôle ROLE_ADMIN , j'ai donc

injecté le service Security dont nous avons parlé précédemment.

Ce Voteur est automatiquement configuré par Symfony, si vous n'avez pas désactivé
l’autoconfiguration, donc ce code est fonctionnel !

Mettons à jour le code du gabarit Twig :


twig

1 {% if is_granted('EDIT', post) %}
2 <div class="section">
3 <a href="{{ path('admin_post_edit', {id: post.id}) }}">
4 <i class="fa fa-edit" aria-hidden="true"></i> {{ 'action.edit_post'|trans }}
5 </a>
6 </div>
7 {% endif %}

Enfin, voici le code du contrôleur avec l'utilisation de l'annotation IsGranted() mise à jour :
php

1 <?php
2
3 use App\Entity\Article;

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 23/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

4 // ...
5
6 class ArticleController extends AbstractController
7 {
8 /**
9 * @IsGranted("EDIT", subject="article")
10 */
11 public function edit(Article $article)
12 {
13 // ...
14 }
15 }

Avec le système des Voteurs et la fonction isGranted(), vous pouvez donc contrôler l'accès aux
différentes actions de votre site, quelle que soit la complexité de vos règles métiers.

Et en bonus, en environnement de développement, le profiler de sécurité est capable de vous dire


quel ou quels Voteurs ont participé au vote. C'est utile si vous ne comprenez pas pourquoi un
utilisateur n'a pas accès à une action, par exemple.

En résumé


Ça y est ! Grâce à ce chapitre, vous savez à présent mettre en place un espace membre pour votre
site. Vous êtes capable de construire un système d'authentification efficace qui garantit la
sécurité de votre application. De cette façon, vous pouvez restreindre l'accès à certaines pages en
exigeant des droits spécifiques à vos visiteurs pour l'afficher.

Mais vous pouvez aller beaucoup plus loin concernant la sécurité avec Symfony ! Si vous le
souhaitez, je vous invite à consulter la documentation officielle de Symfony. Vous pouvez aussi
utiliser la documentation de MakerBundle, le bundle communautaire, qui permet d'obtenir très
rapidement un espace utilisateur complet.

ll y a deux parties à distinguer dans le processus de sécurité

l'authentification, permet d'identifier l'utilisateur :


l'autorisation, vérifie son identité et autorise, ou non, l'accès au contenu demandé.

Grâce au fichier de configuration security.yaml, vous pouvez paramétrer chaque élément de la


sécurité, notamment :

le firewall pour l'authentification


le contrôle d'accès pour l'autorisation, en appliquant des règles sur des URL ou les
méthodes des contrôleurs, selon vos besoins.

Vous pouvez définir des rôles pour les visiteurs pour établir des droits d'accès. Nous pouvons
contrôler les autorisations d'un utilisateur authentifié partout dans nos applications :

dans nos contrôleurs ;


dans nos vues ;

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 24/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

dans nos services...

et de façon très fine à l'aide du système de "Voteurs".

Dans la prochaine partie de ce cours, vous apprendrez comment développer une application de
qualité et la déployer en production.

À tout de suite !

INDIQUER QUE CE CHAPITRE N'EST PAS TERMINÉ

GÉREZ VOS DONNÉES AVEC QUIZ : DYNAMISEZ VOS PAGES À


 
DOCTRINE ORM L’AIDE DE TWIG ET DOCTRINE ORM

Le professeur
Mickaël Andrieu
Consultant et Formateur Web / Data

OPENCLASSROOMS

OPPORTUNITÉS

AIDE

POUR LES ENTREPRISES

EN PLUS

Français

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 25/26
18/07/2022 07:16 Sécurisez l'accès de votre site web - Construisez un site web à l’aide du framework Symfony 5 - OpenClassrooms

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-5/5654131-securisez-lacces-de-votre… 26/26

Vous aimerez peut-être aussi