-
Notifications
You must be signed in to change notification settings - Fork 1
Security
Le fichier de configuration de la sécurité
# app/config/security.yml
jms_security_extra:
secure_all_services: false
expressions: true
security:
encoders: # Encoders pour défnir comment les mot de passe seront cryptés.
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
access_control:
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
- Section role_hierarchy : La notion de « rôle » est au centre du processus d'autorisation. On assigne un ou plusieurs rôles à chaque utilisateur, et chaque ressource nécessite un ou plusieurs rôles. Ainsi, lorsqu'un utilisateur tente d'accéder à une ressource, le contrôleur d'accès vérifie s'il dispose du ou des rôles requis par la ressource. Si c'est le cas, l'accès est accordé. Sinon, l'accès est refusé.
Cette section de la configuration dresse la hiérarchie des rôles. Ainsi, le rôle ROLE_USER est compris dans le rôle ROLE_ADMIN. Cela signifie que si votre page requiert le rôle ROLE_USER, et qu'un utilisateur disposant du rôle ROLE_ADMIN tente d'y accéder, il sera autorisé, car en disposant du rôle d'administrateur, il dispose également du rôle ROLE_USER.
Les noms des rôles n'ont pas d'importance, si ce n'est qu'ils doivent commencer par « ROLE_ ».
-
Section providers : Un provider est un fournisseur d'utilisateurs. Les firewalls s'adressent aux providers pour récupérer les utilisateurs pour les identifier.
-
Section access_control : Comme on l'a vu, le contrôle d'accès (ou access control en anglais) va s'occuper de déterminer si le visiteur a les bons droits (rôles) pour accéder à la ressource demandée. Il y a différents moyens d'utiliser les contrôles d'accès :
-
Soit ici depuis la configuration, en appliquant des règles sur des URL. On sécurise ainsi un ensemble d'URL en une seule ligne, par exemple toutes celles qui commencent par /admin.
-
Soit directement dans les contrôleurs, en appliquant des règles sur les méthodes des contrôleurs. On peut ainsi appliquer des règles différentes selon des paramètres, vous êtes très libres.
Ces deux moyens d'utiliser la même protection par rôle sont très complémentaires, et offrent une flexibilité intéressante, on en reparle.
Récupérer l'utilisateur courant
Pour récupérer les informations sur l'utilisateur courant, qu'il soit anonyme ou non, il faut utiliser le service security.context.
Ce service dispose d'une méthode getToken(), qui permet de récupérer la session de sécurité courante (à ne pas confondre avec la session classique, disponible elle via $request->getSession()). Ce token vaut null si vous êtes hors d'un pare-feu. Et si vous êtes derrière un pare-feu, alors vous pouvez récupérer l'utilisateur courant grâce à $token->getUser().
<?php
// On récupère le service
$security = $container->get('security.context');
// On récupère le token
$token = $security->getToken();
// Si la requête courante n'est pas derrière un pare-feu, $token est null
// Sinon, on récupère l'utilisateur
$user = $token->getUser();
// Si l'utilisateur courant est anonyme, $user vaut « anon. »
// Sinon, c'est une instance de notre entité User, on peut l'utiliser normalement
$user->getUsername();
Comme vous pouvez le voir, il y a pas mal de vérifications à faire, suivant les différents cas possibles. Heureusement, en pratique le contrôleur dispose d'un raccourci permettant d'automatiser cela, il s'agit de la méthode $this->getUser(). Cette méthode retourne :
-
null si la requête n'est pas derrière un pare-feu, ou si l'utilisateur courant est anonyme ;
-
Une instance de User le reste du temps (utilisateur authentifié derrière un pare-feu et non-anonyme).
Depuis une vue Twig
Vous avez accès plus facilement à l'utilisateur directement depuis Twig. Vous savez que Twig dispose de quelques variables globales via la variable {{ app }} ; eh bien, l'utilisateur courant en fait partie, via {{ app.user }} :
Bonjour {{ app.user.username }} - {{ app.user.email }}
Définition des rôles
# app/config/security.yml
security:
role_hierarchy:
ROLE_ADMIN: [ROLE_AUTEUR, ROLE_MODERATEUR] # Un admin hérite des droits d'auteur et de modérateur
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] # On garde ce rôle superadmin, il nous resservira par la suite
Tester les rôles de l'utilisateur
Il existe quatre méthodes pour faire ce test : les annotations, le service security.context, Twig, et les contrôles d'accès. Ce sont quatre façons de faire exactement la même chose.
La méthode de l'annotation permet de sécuriser une méthode de contrôleur. La méthode avec Twig permet de sécuriser l'affichage. La méthode des contrôles d'accès permet de sécuriser des URL.
- Utiliser directement le service security.context
// On teste que l'utilisateur dispose bien du rôle ROLE_AUTEUR if (!$this->get('security.context')->isGranted('ROLE_AUTEUR')) { // Sinon on déclenche une exception « Accès interdit » throw new AccessDeniedHttpException('Accès limité aux auteurs'); }
public function loginAction()
{
// Si le visiteur est déjà identifié, on le redirige vers l'accueil
if ($this->get('security.context')->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return $this->redirect($this->generateUrl('sdzblog_accueil'));
}
$request = $this->getRequest();
$session = $request->getSession();
// On vérifie s'il y a des erreurs d'une précédente soumission du formulaire
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} else {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
return $this->render('SdzUserBundle:Security:login.html.twig', array(
// Valeur du précédent nom d'utilisateur entré par l'internaute
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
'error' => $error,
));
}
- Utiliser les annotations dans un contrôleur
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php
namespace Sdz\BlogBundle\Controller;
// Plus besoin de rajouter le use de l'exception dans ce cas // Mais par contre il faut le use pour les annotations du bundle : use JMS\SecurityExtraBundle\Annotation\Secure;
// …
class BlogController extends Controller { /**
- @Secure(roles="ROLE_AUTEUR") */ public function ajouterAction() { // Plus besoin du if avec le security.context, l'annotation s'occupe de tout ! // Dans cette méthode, vous êtes sûrs que l'utilisateur courant dispose du rôle ROLE_AUTEUR
// … Ici le code d'ajout d'un article qu'on a déjà fait
}
// … }
* Depuis une vue Twig
{# app/Resources/views/layout.html.twig #}
{# ... #}
{# On n'affiche le lien « Ajouter un article » qu'aux auteurs (et admins, qui héritent du rôle auteur) #} {% if is_granted('ROLE_AUTEUR') %} Ajouter un article {% endif %}
{# … #}
* Utiliser les contrôles d'accès
security: access_control: - { path: ^/admin, roles: ROLE_ADMIN, ip: 127.0.0.1, requires_channel: https }