Sécurité


Table des matières

Référence
Exemple de base: l'authentification HTTP
Comment travailler la sécurité: authentification et autorisation
Les pare-feu (authentification)
Contrôles d'accès(autorisation)
L'utilisation d'un formulaire de connexion traditionnelle
Éviter les pièges courants
Créer des routes correctes
Assurez-vous la page de connexion n'est pas sécurisée
Assurez-vous que "/login_check" est derrière un pare-feu
Les multiples pare-feu ne partagent pas le contexte de sécurité
Autorisation
Sécurisation des formats d'URL
Sécurisation par IP
Sécurisation par Channel
Sécurisation d'un contrôleur
Sécurisation des autres services
Access Control Lists (ACL): Sécurisation des objets de base de données individuelles
Les utilisateurs
Que font les utilisateurs qui viennent de? (Fournisseurs d'accès utilisateur)
Indiquer les utilisateurs dans un fichier de configuration
Encodage mot de passe de l'utilisateur
Récupération de l'objet utilisateur
Aide de fournisseurs d'utilisateurs multiples
Rôles
Rôles hiérarchiques
Déconnexion
Contrôle d'accès dans les templates
Contrôle d'accès dans les contrôleurs
Usurpation de l'identité d'un utilisateur
Authentification Stateless
Final Words

Référence

La sécurité est un processus en deux étapes dont le but est d'empêcher un utilisateur d'accéder à une ressource qu'il / elle ne devrait pas avoir accès.

Dans la première étape du processus, le système de sécurité identifie qui est l'utilisateur en exigeant à l'utilisateur de présenter une sorte d'identification. C'est ce qu'on appelle l'authentification, et cela signifie que le système essaie de savoir qui vous êtes.

Une fois que le système sait qui vous êtes, l'étape suivante consiste à déterminer si vous devriez avoir accès à une ressource donnée. Cette partie du processus est appelé l'autorisation, et cela signifie que le système vérifie pour voir si vous avez des privilèges pour effectuer une certaine action.

Puisque la meilleure façon d'apprendre est de voir un exemple, nous allons plonger en plein dedans

Symfony composant de sécurité est disponible comme une bibliothèque autonome PHP pour une utilisation à l'intérieur de n'importe quel projet PHP.

Exemple de base: l'authentification HTTP

Le composant de sécurité peut être configuré via la configuration de votre application. En fait, les configurations de sécurité les plus standards sont juste une question d'utiliser la bonne configuration. La configuration suivante indique Symfony, pour garantir une URL correspondant à /admin/* et à demander à l'utilisateur des informations d'identification en utilisant l'authentification de base HTTP (c.-à-d. old-school nom d'utilisateur / mot de passe ):

Version Yaml

# app/config/security.yml
security:
    firewalls:
        secured_area:
            pattern:    ^/
            anonymous: ~
            http_basic:
                realm: "Secured Demo Area"

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

    providers:
        in_memory:
            users:
                ryan:  { password: ryanpass, roles: 'ROLE_USER' }
                admin: { password: kitten, roles: 'ROLE_ADMIN' }

    encoders:
        Symfony\Component\Security\Core\User\User: plaintext

Version Xml

<!-- app/config/security.xml -->
<srv:container xmlns="http://symfony.com/schema/dic/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <config>
        <firewall name="secured_area" pattern="^/">
            <anonymous />
            <http-basic realm="Secured Demo Area" />
        </firewall>

        <access-control>
            <rule path="^/admin" role="ROLE_ADMIN" />
        </access-control>

        <provider name="in_memory">
            <user name="ryan" password="ryanpass" roles="ROLE_USER" />
            <user name="admin" password="kitten" roles="ROLE_ADMIN" />
        </provider>

        <encoder class="Symfony\Component\Security\Core\User\User" algorithm="plaintext" />
    </config>
</srv:container>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' = > array(
        'secured_area' = > array(
            'pattern' = > '^/',
            'anonymous' = > array(),
            'http_basic' = > array(
                'realm' = > 'Secured Demo Area',
            ),
        ),
    ),
    'access_control' = > array(
        array('path' = > '^/admin', 'role' = > 'ROLE_ADMIN'),
    ),
    'providers' = > array(
        'in_memory' = > array(
            'users' = > array(
                'ryan' = > array('password' = > 'ryanpass', 'roles' = > 'ROLE_USER'),
                'admin' = > array('password' = > 'kitten', 'roles' = > 'ROLE_ADMIN'),
            ),
        ),
    ),
    'encoders' = > array(
        'Symfony\Component\Security\Core\User\User' = > 'plaintext',
    ),
));

Une distribution standard de symfony sépare la configuration de la sécurité dans un fichier séparé (par exemple app/config/security.yml). Si vous n'avez pas de dossier de sécurité distinct, vous pouvez mettre la configuration directement dans votre fichier de configuration principal (par exemple app/config/config.yml).

Le résultat final de cette configuration est un système de sécurité entièrement fonctionnel qui ressemble à ce qui suit:

Examinons brièvement la manière dont la sécurité fonctionne et comment chaque partie de la configuration entre en jeu.

Comment travailler la sécurité: authentification et autorisation

Système de sécurité de Symfony fonctionne en déterminant qui est un utilisateur (c.-à-d. authentification) et puis de vérifier pour voir si cet utilisateur doit avoir accès à une ressource ou une URL spécifique.

Les pare-feu (authentification)

Quand un utilisateur effectue une requête vers une URL qui est protégé par un pare-feu, le système de sécurité est activé. Le travail du pare-feu est de déterminer si oui ou non l'utilisateur doit être authentifié, et s'il le fait, pour envoyer une réponse à l'utilisateur qui lance le processus d'authentification.

Un pare-feu est activé lorsque l'URL d'une requête entrante correspond régulièrement le pare-feu configuré la valeur de configuration modèle d'expression. Dans cet exemple, le motif (^ /) va correspondre à chaque demande entrante. Le fait que le pare-feu est activé ne signifie pas, cependant, que le nom d'utilisateur d'authentification HTTP et la boîte de mot de passe est affiché pour chaque URL. Par exemple, n'importe quel utilisateur peut accéder à /foo sans être invité à vous authentifier.

Cela fonctionne d'abord parce que le pare-feu autorise les utilisateurs anonymes via le paramètre de configuration anonyme. En d'autres termes, le pare-feu ne requiert pas l'utilisateur de s'authentifier entièrement immédiatement. Et parce que pas de rôle spécial est nécessaire pour accéder à /foo (dans la section access_control), la demande peut être satisfaite sans jamais demander à l'utilisateur de s'authentifier.

Si vous retirez la clé anonyme, le pare-feu fera toujours un utilisateur entièrement authentifier immédiatement.

Contrôles d'accès(autorisation)

Si les demandes d'un utilisateur /admin/foo, toutefois, le processus se comporte différemment. C'est à cause de la section de configuration access_control qui dit que toute URL correspondant au modèle d'expression régulière ^admin (c.-à-d. /admin ou quoi que ce soit correspondant à /admin/*) nécessite le rôle ROLE_ADMIN. Les rôles sont la base pour la plupart d'autorisation: un utilisateur peut accéder à /admin/foo que si elle a le rôle ROLE_ADMIN.

Comme avant, lorsque l'utilisateur fait la demande à l'origine, le pare-feu ne demande pas une pièce d'identité. Cependant, dès que la couche de contrôle d'accès refuse l'accès des utilisateurs (parce que l'utilisateur anonyme n'est pas le rôle ROLE_ADMIN), les sauts de pare-feu entre en action et lance le processus d'authentification. Le processus d'authentification repose sur le mécanisme d'authentification que vous utilisez. Par exemple, si vous utilisez la méthode d'authentification formulaire de connexion, l'utilisateur sera redirigé vers la page de connexion. Si vous utilisez l'authentification HTTP, l'utilisateur sera envoyé une réponse HTTP 401 afin que l'utilisateur voit le nom d'utilisateur et la boîte de mot de passe.

L'utilisateur a maintenant la possibilité de présenter ses lettres de noblesse vers l'application. Si les informations sont valides, la demande initiale peut être re-jugée.

Dans cet exemple, l'utilisateur s'authentifie avec succès ryan avec le pare-feu. Mais depuis ryan n'a pas le rôle ROLE_ADMIN, il est toujours refuser l'accès à /admin/foo. En fin de compte, cela signifie que l'utilisateur verra une sorte de message indiquant que l'accès a été refusé.

Lorsque Symfony nie l'accès des utilisateurs, l'utilisateur voit un message d'erreur et reçoit un code d'état HTTP 403 (Refusé). Vous pouvez personnaliser l'écran d'erreur d'accès refusé en suivant les instructions dans le Erreur Pages d'entrée recette de cuisine pour personnaliser la page d'erreur 403.

Enfin, si les demandes des utilisateurs admin /admin/foo, un processus semblable a lieu, sauf que maintenant, après avoir été authentifié, la couche de contrôle d'accès vous permettra de passer à travers la demande:

[[images/symfony2security_admin_role_access.png

Le débit est requis lorsque l'utilisateur demande une ressource protégée est simple, mais incroyablement flexible. Comme vous le verrez plus tard, l'authentification peut être manipulé dans un certain nombre de façons, y compris via un formulaire de connexion, de certificats X.509, ou par authentification de l'utilisateur via Twitter. Quelle que soit la méthode d'authentification, le flux de demandes est toujours le même:

Le processus exact dépend en fait un peu le mécanisme d'authentification qui vous utilisez. Par exemple, lorsque l'aide du login formulaire, l'utilisateur soumet ses informations d'identification à une URL qui traite le formulaire (par exemple /login_check), puis est redirigé vers l'URL demandée à l'origine (par exemple /admin/foo). Mais avec l'authentification HTTP, l'utilisateur soumet ses informations d'identification directement à l'URL d'origine (par exemple /admin/foo) et puis la page est renvoyée à l'utilisateur dans cette même demande (c.-à-d pas rediriger).

Ces types de particularités ne devraient pas vous causer des problèmes, mais ils sont bons à garder à l'esprit.

Vous apprendrez également plus loin comment quelque chose peut être fixé dans Symfony2, y compris les contrôleurs spécifiques, des objets ou de méthodes, même PHP.

L'utilisation d'un formulaire de connexion traditionnelle

Jusqu'ici, vous avez vu comment recouvrent votre application sous un pare-feu, puis de protéger l'accès à certaines zones avec des rôles. En utilisant l'authentification HTTP, vous pouvez facilement exploiter le natif nom d'utilisateur/mot de passe boîte offerte par tous les navigateurs. Cependant, Symfony supporte de nombreux mécanismes d'authentification de la boîte. Pour plus de détails sur chacun d'eux, voir la référence de configuration de sécurité .

Dans cette section, vous allez améliorer ce processus en permettant à l'utilisateur de s'authentifier via un formulaire de connexion HTML traditionnel.

D'abord, activez formulaire de connexion sous votre pare-feu:

Version Yaml

# app/config/security.yml
security:
    firewalls:
        secured_area:
            pattern:    ^/
            anonymous: ~
            form_login:
                login_path:  /login
                check_path:  /login_check

Version Xml

<!-- app/config/security.xml -->
<srv:container xmlns="http://symfony.com/schema/dic/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <config>
        <firewall name="secured_area" pattern="^/">
            <anonymous />
            <form-login login_path="/login" check_path="/login_check" />
        </firewall>
    </config>
</srv:container>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' = > array(
        'secured_area' = > array(
            'pattern' = > '^/',
            'anonymous' = > array(),
            'form_login' = > array(
                'login_path' = > '/login',
                'check_path' = > '/login_check',
            ),
        ),
    ),
));

Si vous n'avez pas besoin de personnaliser votre login_path ou les valeurs check_path (les valeurs utilisées ici sont les valeurs par défaut), vous pouvez raccourcir votre configuration:

Version Yaml

form_login: ~

Version Xml

<form-login />

Version Php

'form_login' = > array(),

Maintenant, lorsque le système de sécurité déclenche le processus d'authentification, il sera rediriger l'utilisateur vers le formulaire de login (/login par défaut). La mise en œuvre de cette forme de connexion est visuellement votre travail. Tout d'abord, de créer deux voies: l'une qui permettra d'afficher le formulaire de connexion (par exemple /login) et un qui va gérer la soumission du formulaire de connexion (par exemple /login_check):

Version Yaml

# app/config/routing.yml
login:
    pattern:   /login
    defaults:  { _controller: AcmeSecurityBundle:Security:login }
login_check:
    pattern:   /login_check

Version Xml

<!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>

<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="login" pattern="/login">
        <default key="_controller">AcmeSecurityBundle:Security:login</default>
    </route>
    <route id="login_check" pattern="/login_check" />

</routes>

Version Php

// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add('login', new Route('/login', array(
    '_controller' = > 'AcmeDemoBundle:Security:login',
)));
$collection->add('login_check', new Route('/login_check', array()));

return $collection;

Vous n'aurez pas besoin de mettre en œuvre un contrôleur pour l'URL /login_check le pare-feu saura automatiquement attraper et transformer toute forme soumis à cette URL. Il est facultatif, mais utile, pour créer un itinéraire de sorte que vous pouvez l'utiliser pour générer l'URL soumission du formulaire dans le modèle de connexion ci-dessous.

Notez que le nom de la route de connexion n'est pas important. Ce qui est important est que l'URL de la route (/login) correspond à la valeur de configuration login_path, comme c'est là que le système de sécurité sera de rediriger les utilisateurs qui ont besoin de se connecter.

Ensuite, créez le contrôleur qui permettra d'afficher le formulaire de connexion:

// src/Acme/SecurityBundle/Controller/Main;
namespace Acme\SecurityBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;

class SecurityController extends Controller
{
    public function loginAction()
    {
        $request = $this->getRequest();
        $session = $request->getSession();

        // get the login error if there is one
        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('AcmeSecurityBundle:Security:login.html.twig', array(
            // last username entered by the user
            'last_username' = > $session->get(SecurityContext::LAST_USERNAME),
            'error'         = > $error,
        ));
    }
}

Ne laissez pas ce contrôleur que vous confondez. Comme vous le verrez dans un instant, lorsque l'utilisateur soumet le formulaire, le système de sécurité gère automatiquement la soumission du formulaire pour vous. Si l'utilisateur a soumis un nom d'utilisateur ou mot de passe invalide, ce contrôleur lit le formulaire de soumission d'erreur du système de sécurité afin qu'il puisse être affiché à l'utilisateur.

En d'autres termes, votre travail consiste à afficher le formulaire de connexion et les erreurs de connexion qui peuvent avoir eu lieu, mais le système de sécurité lui-même prend soin de vérifier le nom d'utilisateur et mot de passe soumis et l'authentification de l'utilisateur.

Enfin, créez le modèle correspondant:

Version Twig

{# src/Acme/SecurityBundle/Resources/views/Security/login.html.twig #}
{% if error %}
    <div>{{ error.message }}</div>
{% endif %}

<form action="{{ path('login_check') }}" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="_username" value="{{ last_username }}" />

    <label for="password">Password:</label>
    <input type="password" id="password" name="_password" />

    {#
        If you want to control the URL the user is redirected to on success (more details below)
        <input type="hidden" name="_target_path" value="/account" />
    #}

    <button type="submit">login</button>
</form>

Version Php

<?php // src/Acme/SecurityBundle/Resources/views/Security/login.html.php ?>
<?php if ($error): ?>
    <div><?php echo $error->getMessage() ?></div>
<?php endif; ?>

<form action="<?php echo $view['router']->generate('login_check') ?>" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="_username" value="<?php echo $last_username ?>" />

    <label for="password">Password:</label>
    <input type="password" id="password" name="_password" />

    <!--
        If you want to control the URL the user is redirected to on success (more details below)
        <input type="hidden" name="_target_path" value="/account" />
    -->

    <button type="submit">login</button>
</form>

La variable d'erreur passé dans le modèle est une instance de AuthenticationException . Il peut contenir plus d'informations - même sensibles ou des informations - sur l'échec d'authentification, afin de l'utiliser à bon escient!

Le formulaire comporte peu d'exigences. Tout d'abord, en soumettant le formulaire à /login_check (via la route login_check), le système de sécurité d'intercepter l'envoi du formulaire et de traiter le formulaire pour vous automatiquement. Deuxièmement, le système de sécurité s'attend à ce que les champs soumis à être appelé _USERNAME et _PASSWORD (ces noms de champs peuvent être configurés ).

Et c'est tout! Lorsque vous soumettez le formulaire, le système de sécurité vérifie automatiquement les informations d'identification de l'utilisateur et soit authentifier l'utilisateur ou envoyer l'utilisateur vers le formulaire de connexion où l'erreur peut être affiché.

Passons en revue l'ensemble du processus:

Par défaut, si les crédits présentés sont corrects, l'utilisateur sera redirigé vers la page d'origine qui a été demandée (par exemple /admin foo). Si l'utilisateur à l'origine va droit à la page de connexion, il sera redirigé vers la page d'accueil. Cela peut être hautement personnalisé, vous permettant, par exemple, rediriger l'utilisateur vers une URL spécifique.

Pour plus de détails à ce sujet et la façon de personnaliser le processus de connexion sous forme en général, voir Comment personnaliser votre Login Form .

Éviter les pièges courants

Lorsque vous configurez votre formulaire de connexion, faites attention aux quelques pièges communs.

Créer des routes correctes

Tout d'abord, assurez-vous que vous avez défini les routes /login et /login_check correctement et qu'ils correspondent à la configuration et les valeurs login_path check_path. Une mauvaise configuration ici peut signifier que vous êtes redirigé vers une page d'erreur 404 au lieu de la page de connexion, ou que la présentation du formulaire de connexion ne fait rien (vous venez de voir le formulaire de connexion, encore et encore).

Assurez-vous la page de connexion n'est pas sécurisée

En outre, assurez-vous que la page de connexion ne nécessite pas de rôles pour être visualisées. Par exemple, la configuration suivante - ce qui nécessite le rôle ROLE_ADMIN pour toutes les URL (y compris l'URL /login), fera une boucle de redirection:

Version Yaml

<src lang="php">
access_control:
    - { path: ^/, roles: ROLE_ADMIN }

Version Xml

<access-control>
    <rule path="^/" role="ROLE_ADMIN" />
</access-control>

Version Php

'access_control' = > array(
    array('path' = > '^/', 'role' = > 'ROLE_ADMIN'),
),

Retrait du contrôle d'accès sur l'URL /login résout le problème:

Version Yaml

access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, roles: ROLE_ADMIN }

Version Xml

<access-control>
    <rule path="^/login" role="IS_AUTHENTICATED_ANONYMOUSLY" />
    <rule path="^/" role="ROLE_ADMIN" />
</access-control>

Version Php

'access_control' = > array(
    array('path' = > '^/login', 'role' = > 'IS_AUTHENTICATED_ANONYMOUSLY'),
    array('path' = > '^/', 'role' = > 'ROLE_ADMIN'),
),

En outre, si votre pare-feu ne permet pas les utilisateurs anonymes, vous aurez besoin de créer un pare-feu spécial qui permet aux utilisateurs anonymes de se connecter sur la page de connexion:

Version Yaml

firewalls:
    login_firewall:
        pattern:    ^/login$
        anonymous:  ~
    secured_area:
        pattern:    ^/
        form_login: ~

Version Xml

<firewall name="login_firewall" pattern="^/login$">
    <anonymous />
</firewall>
<firewall name="secured_area" pattern="^/">
    <form_login />
</firewall>

Version Php

'firewalls' = > array(
    'login_firewall' = > array(
        'pattern' = > '^/login$',
        'anonymous' = > array(),
    ),
    'secured_area' = > array(
        'pattern' = > '^/',
        'form_login' = > array(),
    ),
),

Assurez-vous que "/login_check" est derrière un pare-feu

Ensuite, assurez-vous que l'URL de votre check_path (par exemple /login_check) se trouve derrière le pare-feu que vous utilisez pour votre formulaire de connexion (dans cet exemple, le pare-feu unique correspond à toutes les URL, y compris /login_check). Si /login_check ne correspond à aucun pare-feu, vous recevrez un Impossible de trouver le contrôleur pour le chemin "/login_check" exception.

Les multiples pare-feu ne partagent pas le contexte de sécurité

Si vous utilisez plusieurs pare-feu et que vous authentifier un pare-feu, vous ne serez pas authentifiés par rapport à toutes les autres pare-feu automatiquement. Les Pare-feu différents sont comme des systèmes de sécurité différents. C'est pourquoi, pour la plupart des applications, avoir un pare-feu principal est suffisant.

Autorisation

La première étape en matière de sécurité est toujours l'authentification: le processus de vérification qui est l'utilisateur. Avec Symfony, l'authentification ne peut être fait en aucune façon via un formulaire de connexion, d'authentification HTTP de base, ou même via Facebook.

Une fois que l'utilisateur a été authentifié, l'autorisation commence. Autorisation fournit une méthode standard et puissante pour décider si un utilisateur peut accéder à une ressource (une URL, un modèle d'objet, un appel de méthode, ...). Cela fonctionne en attribuant des rôles spécifiques à chaque utilisateur, et nécessite alors des rôles différents pour différentes ressources.

Le processus d'autorisation a deux faces différentes:

Dans cette section, vous allez vous concentrer sur la façon d'obtenir des ressources différentes (par exemple URL, les appels de méthode, etc) avec des rôles différents. Plus tard, vous en apprendrez plus sur la façon dont les rôles sont créés et attribués à des utilisateurs.

Sécurisation des formats d'URL

Le moyen le plus simple pour sécuriser une partie de votre demande est d'obtenir un modèle d'URL entière. Vous avez vu ce déjà dans le premier exemple de ce chapitre, où tout correspondant au modèle d'expression régulière ^/admin nécessite le rôle ROLE_ADMIN.

Vous pouvez définir autant de motifs d'URL que vous avez besoin - chacun est une expression régulière.

Version Yaml

# app/config/security.yml
security:
    # ...
    access_control:
        - { path: ^/admin/users, roles: ROLE_SUPER_ADMIN }
        - { path: ^/admin, roles: ROLE_ADMIN }

Version Xml

<!-- app/config/security.xml -->
<config>
    <!-- ... -->
    <rule path="^/admin/users" role="ROLE_SUPER_ADMIN" />
    <rule path="^/admin" role="ROLE_ADMIN" />
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
    'access_control' = > array(
        array('path' = > '^/admin/users', 'role' = > 'ROLE_SUPER_ADMIN'),
        array('path' = > '^/admin', 'role' = > 'ROLE_ADMIN'),
    ),
));

Faire précéder du chemin avec ^ assure que les URL commençant avec le modèle sont mis en correspondance. Par exemple, un chemin de simplement /admin (sans ^) serait correctement correspondre /admin/foo, mais aussi correspondre à des URL comme /foo/admin.

Pour chaque requête entrante, Symfony2 essaie de trouver une règle d'accès d'appariement de contrôle (la première règle trouvée gagne). Si l'utilisateur n'est pas authentifié encore, le processus d'authentification est initiée (c'est à dire l'utilisateur a une chance pour se connecter). Toutefois, si l'utilisateur est authentifié mais n'a pas le rôle nécessaire, un AccessDeniedException exception est levée, que vous pouvez manipuler et transformer en un bel "accès refusé" page d'erreur pour l'utilisateur. Voir Comment faire pour personnaliser les pages d'erreur pour plus d'informations.

Symfony utilise la règle du premier accès de contrôle, il correspond à une URL comme /admin/users/new qui correspondra à la première règle et ne nécessitent que le rôle ROLE_SUPER_ADMIN. Toute URL comme /admin/blog correspondre à la seconde règle et nécessitent ROLE_ADMIN.

Sécurisation par IP

Certaines situations peuvent survenir lorsque vous devrez peut-être restreindre l'accès à une route donnée basée sur IP. Ceci est particulièrement pertinent dans le cas d' Edge Side Includes HTTP Cache ESI, par exemple, qui utilisent une route nommée "_internal". Lorsque ESI est utilisé, la voie _internal est requis par le cache passerelle pour activer les options de mise en cache différents pour les paragraphes au sein d'une page donnée. Cet itinéraire est fourni avec le préfixe ^/_internal par défaut dans l'édition standard (en supposant que vous avez décommenté ces lignes à partir du fichier de routage).

Voici un exemple de la façon dont vous pourriez sécuriser cette voie de l'accès à l'extérieur:

Version Yaml

# app/config/security.yml
security:
    # ...
    access_control:
        - { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }

Version Xml

<access-control>
    <rule path="^/_internal" role="IS_AUTHENTICATED_ANONYMOUSLY" ip="127.0.0.1" />
</access-control>

Version Php

'access_control' = > array(
    array('path' = > '^/_internal', 'role' = > 'IS_AUTHENTICATED_ANONYMOUSLY', 'ip' = > '127.0.0.1'),
),

Sécurisation par Channel

Tout comme la sécurisation basée sur l'IP, ce qui nécessite l'utilisation de SSL est aussi simple que l'ajout d'une entrée access_control nouvelle:

Version Yaml

# app/config/security.yml
security:
    # ...
    access_control:
        - { path: ^/cart/checkout, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }

Version Xml

<access-control>
    <rule path="^/cart/checkout" role="IS_AUTHENTICATED_ANONYMOUSLY" requires_channel="https" />
</access-control>

Version Php

'access_control' = > array(
    array('path' = > '^/cart/checkout', 'role' = > 'IS_AUTHENTICATED_ANONYMOUSLY', 'requires_channel' = > 'https'),
),

Sécurisation d'un contrôleur

La protection de votre application basée sur des schémas URL est facile, mais peut-être pas assez fine, dans certains cas. Lorsque cela est nécessaire, vous pouvez facilement forcer l'autorisation de l'intérieur d'un contrôleur:

use Symfony\Component\Security\Core\Exception\AccessDeniedException;
// ...

public function helloAction($name)
{
    if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
        throw new AccessDeniedException();
    }

    // ...
}

Vous pouvez également choisir d'installer et d'utiliser le JMSSecurityExtraBundle option, qui peut garantir votre contrôleur à l'aide des annotations:

use JMS\SecurityExtraBundle\Annotation\Secure;

/**
 * @Secure(roles="ROLE_ADMIN")
 */
public function helloAction($name)
{
    // ...
}

Pour plus d'informations, consultez le JMSSecurityExtraBundle documentation. Si vous utilisez la distribution standard de symfony, ce bundle est disponible par défaut. Si non, vous pouvez facilement télécharger et l'installer.

Sécurisation des autres services

En fait, rien dans Symfony peut être protégé en utilisant une stratégie similaire à celui vu dans la section précédente. Par exemple, supposons que vous avez un service (ie une classe PHP) dont le travail consiste à envoyer des emails d'un utilisateur à un autre. Vous pouvez restreindre l'utilisation de cette classe - peu importe où il est utilisé à partir de - pour les utilisateurs qui ont un rôle spécifique.

Pour plus d'informations sur la façon dont vous pouvez utiliser le composant de sécurité pour sécuriser les services et des méthodes différentes dans votre application, consultez Comment sécuriser tout service ou d'une méthode dans votre application

Access Control Lists (ACL): Sécurisation des objets de base de données individuelles

Imaginez que vous êtes la conception d'un système de blog où les utilisateurs peuvent commenter vos messages. Maintenant, vous voulez qu'un utilisateur soit en mesure de modifier ses propres commentaires, mais pas ceux des autres utilisateurs. En outre, en tant qu'administrateur, vous vous voulez être en mesure de modifier tous les commentaires.

Le composant de sécurité est livré avec un contrôle d'accès liste optionnelle (ACL) du système que vous pouvez utiliser lorsque vous avez besoin pour contrôler l'accès à des instances individuelles d'un objet dans votre système. Sans ACL, vous pouvez sécuriser votre système de sorte que seuls certains utilisateurs peuvent modifier Blog commentaires en général. Mais avec les ACL, vous pouvez restreindre ou autoriser l'accès sur une base commentaire par commentaire.

Pour plus d'informations, consultez l'article livre de recettes: Access Control Lists (ACL) .

Les utilisateurs

Dans les sections précédentes, vous avez appris comment vous pouvez protéger les ressources différentes en exigeant un ensemble de rôles pour une ressource. Dans cette section, nous allons explorer l'autre côté de l'autorisation: les utilisateurs.

Que font les utilisateurs qui viennent de? (Fournisseurs d'accès utilisateur)

Lors de l'authentification, l'utilisateur soumet un ensemble d'informations d'identification (généralement un nom d'utilisateur et mot de passe). Le travail du système d'authentification est de faire correspondre ces informations d'identification contre certains groupe d'utilisateurs. Alors d'où vient cette liste des utilisateurs qui viennent de ?

En Symfony2, les utilisateurs peuvent venir de n'importe où - un fichier de configuration, une table de base de données, un service Web, ou toute autre chose dont vous pouvez rêver. Tout ce qui fournit un ou plusieurs utilisateurs au système d'authentification est connu comme un "fournisseur de l'utilisateur". Symfony2 est livré en standard avec les deux fournisseurs les plus courantes des utilisateurs: celui que les utilisateurs des charges à partir d'un fichier de configuration et celui qui charge les utilisateurs d'une table de base de données.

Indiquer les utilisateurs dans un fichier de configuration

Le meilleur moyen de spécifier vos utilisateurs est directement dans un fichier de configuration. En fait, vous avez vu cette déjà dans l'exemple dans ce chapitre.

Version Yaml

# app/config/security.yml
security:
    # ...
    providers:
        default_provider:
            users:
                ryan:  { password: ryanpass, roles: 'ROLE_USER' }
                admin: { password: kitten, roles: 'ROLE_ADMIN' }

Version Xml

<!-- app/config/security.xml -->
<config>
    <!-- ... -->
    <provider name="default_provider">
        <user name="ryan" password="ryanpass" roles="ROLE_USER" />
        <user name="admin" password="kitten" roles="ROLE_ADMIN" />
    </provider>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
    'providers' = > array(
        'default_provider' = > array(
            'users' = > array(
                'ryan' = > array('password' = > 'ryanpass', 'roles' = > 'ROLE_USER'),
                'admin' = > array('password' = > 'kitten', 'roles' = > 'ROLE_ADMIN'),
            ),
        ),
    ),
));

Ce fournisseur de l'utilisateur est appelé le «in-memory" fournisseur de l'utilisateur, puisque les utilisateurs ne sont pas stockées dans une base de données. L'objet réel de l'utilisateur est fourni par Symfony ( l'utilisateur ).

Tout fournisseur de l'utilisateur peut charger directement les utilisateurs de la configuration en spécifiant le paramètre de configuration des utilisateurs et la liste des utilisateurs en dessous.

Si votre nom d'utilisateur est complètement numérique (par exemple 77) ou contient un tiret (par exemple nom d'utilisateur), vous devez utiliser cette syntaxe alternative lorsque spécifiant les utilisateurs en YAML:

users:
    - { name: 77, password: pass, roles: 'ROLE_USER' }
    - { name: user-name, password: pass, roles: 'ROLE_USER' }

Pour les plus petits sites, cette méthode est rapide et facile à installer. Pour les systèmes plus complexes, vous aurez envie de charger vos utilisateurs à partir de la base de données.

Chargement utilisateurs de la base de la Database

Si vous souhaitez charger vos utilisateurs via l'ORM Doctrine, vous pouvez facilement faire cela en créant une classe d'utilisateur et la configuration du fournisseur de l'entité.

Avec cette approche, vous devez d'abord créer votre propre classe User, qui sera stockée dans la base de données.

// src/Acme/UserBundle/Entity/User.php
namespace Acme\UserBundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class User implements UserInterface
{
    /**
     * @ORM\Column(type="string", length="255")
     */
    protected $username;

    // ...
}

En ce qui concerne le système de sécurité est en cause, la seule exigence pour votre classe d'utilisateur personnalisé, c'est qu'il met en œuvre le InterfaceUtilisateur interface. Cela signifie que votre concept d'un "utilisateur" peut être n'importe quoi, tant qu'il implémente cette interface.

L'objet utilisateur sera sérialisé et enregistré dans la session lors de demandes, il est donc recommandé que vous implémenter l'interface Serializable dans votre objet utilisateur. Ceci est particulièrement important si votre classe Utilisateur dispose d'un classe parente avec des propriétés privées.

Ensuite, configurer un fournisseur de l'utilisateur entité, et qu'il pointe vers votre classe d'utilisateur:

Version Yaml

# app/config/security.yml
security:
    providers:
        main:
            entity: { class: Acme\UserBundle\Entity\User, property: username }

Version Xml

<!-- app/config/security.xml -->
<config>
    <provider name="main">
        <entity class="Acme\UserBundle\Entity\User" property="username" />
    </provider>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'providers' = > array(
        'main' = > array(
            'entity' = > array('class' = > 'Acme\UserBundle\Entity\User', 'property' = > 'username'),
        ),
    ),
));

Avec l'introduction de ce nouveau fournisseur, le système d'authentification va tenter de charger un objet utilisateur à partir de la base de données en utilisant le champ nom d'utilisateur de cette classe.

Cet exemple est juste destinée à vous montrer l'idée de base derrière le fournisseur de l'entité. Pour un exemple complet de travail, voir Comment charger Utilisateurs de sécurité à partir de la base de données (le fournisseur de l'entité)

Pour plus d'informations sur la création de votre propre fournisseur personnalisé (par exemple si vous avez besoin pour charger les utilisateurs via un service Web), voir Comment faire pour créer un fournisseur de l'utilisateur personnalisée .

Encodage mot de passe de l'utilisateur

Jusqu'à présent, pour plus de simplicité, tous les exemples ont stocké des mots de passe des utilisateurs en texte clair (si ces utilisateurs sont stockés dans un fichier de configuration ou dans une base de données quelque part). Bien sûr, dans une application réelle, vous aurez envie de coder vos mots de passe des utilisateurs pour des raisons de sécurité. Ceci est facilement accompli par la cartographie de votre classe User à l'un de plusieurs built-in "codeurs". Par exemple, pour stocker vos utilisateurs dans la mémoire, mais occultent leurs mots de passe via sha1, procédez comme suit:

Version Yaml

# app/config/security.yml
security:
    # ...
    providers:
        in_memory:
            users:
                ryan:  { password: bb87a29949f3a1ee0559f8a57357487151281386, roles: 'ROLE_USER' }
                admin: { password: 74913f5cd5f61ec0bcfdb775414c2fb3d161b620, roles: 'ROLE_ADMIN' }

    encoders:
        Symfony\Component\Security\Core\User\User:
            algorithm:   sha1
            iterations: 1
            encode_as_base64: false

Version Xml

<!-- app/config/security.xml -->
<config>
    <!-- ... -->
    <provider name="in_memory">
        <user name="ryan" password="bb87a29949f3a1ee0559f8a57357487151281386" roles="ROLE_USER" />
        <user name="admin" password="74913f5cd5f61ec0bcfdb775414c2fb3d161b620" roles="ROLE_ADMIN" />
    </provider>

    <encoder class="Symfony\Component\Security\Core\User\User" algorithm="sha1" iterations="1" encode_as_base64="false" />
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
    'providers' = > array(
        'in_memory' = > array(
            'users' = > array(
                'ryan' = > array('password' = > 'bb87a29949f3a1ee0559f8a57357487151281386', 'roles' = > 'ROLE_USER'),
                'admin' = > array('password' = > '74913f5cd5f61ec0bcfdb775414c2fb3d161b620', 'roles' = > 'ROLE_ADMIN'),
            ),
        ),
    ),
    'encoders' = > array(
        'Symfony\Component\Security\Core\User\User' = > array(
            'algorithm'         = > 'sha1',
            'iterations'        = > 1,
            'encode_as_base64'  = > false,
        ),
    ),
));

En définissant les itérations à 1 et les encode_as_base64 à false, le mot de passe est tout simplement de fonctionner grâce à l'algorithme sha1 une seule fois et sans aucun encodage supplémentaire. Vous pouvez maintenant calculer le mot de passe crypté, soit par programme (par exemple de hachage ("sha1", "ryanpass ')) ou via un outil en ligne comme fonctions-online.com

Si vous créez vos utilisateurs dynamiquement (et les stocker dans une base de données), vous pouvez utiliser des algorithmes de hachage encore plus sévères et ensuite s'appuyer sur un objet encodeur mot de passe réel pour vous aider à coder les mots de passe. Par exemple, supposons que votre objet utilisateur est Acme\UserBundle\Entity\User (comme dans l'exemple ci-dessus). Tout d'abord, configurer l'encodeur pour cet utilisateur:

Version Yaml

# app/config/security.yml
security:
    # ...

    encoders:
        Acme\UserBundle\Entity\User: sha512

Version Xml

<!-- app/config/security.xml -->
<config>
    <!-- ... -->

    <encoder class="Acme\UserBundle\Entity\User" algorithm="sha512" />
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    // ...

    'encoders' = > array(
        'Acme\UserBundle\Entity\User' = > 'sha512',
    ),
));

Dans ce cas, vous utilisez le plus fort algorithme SHA512. En outre, puisque vous avez tout simplement précisé l'algorithme (sha512) comme une chaîne, le système sera par défaut le hachage de mot de passe 5000 fois dans une rangée, puis de l'encoder en base64. En d'autres termes, le mot de passe a été grandement obscurci de sorte que le mot de passe crypté ne peut être décodé (c.-à-vous ne peut pas déterminer le mot de passe à partir du mot de passe crypté).

Si vous avez une sorte de formulaire d'inscription pour les utilisateurs, vous devrez être en mesure de déterminer le mot de passe crypté de sorte que vous pouvez le configurer sur votre nom d'utilisateur. Peu importe quel algorithme vous configurez pour votre objet utilisateur, le mot de passe crypté peut toujours être déterminée de la façon suivante à partir d'un contrôleur:

$factory = $this->get('security.encoder_factory');
$user = new Acme\UserBundle\Entity\User();

$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword('ryanpass', $user->getSalt());
$user->setPassword($password);

Récupération de l'objet utilisateur

Après l'authentification, l'objet d'utilisateur de l'utilisateur actuel peut être consulté via le service security.context. De l'intérieur d'un contrôleur, ce qui ressemblerait à ceci:

public function indexAction()
{
    $user = $this->get('security.context')->getToken()->getUser();
}

Les utilisateurs anonymes sont techniquement authentifié, ce qui signifie que la méthode isAuthenticated () d'un objet utilisateur anonyme renverra vrai. Pour vérifier si votre nom d'utilisateur est effectivement authentifié, vérifiez le rôle IS_AUTHENTICATED_FULLY.

Dans un modèle Twig cet objet peut être consulté via la touche app.user, qui appelle la méthode GlobalVariables::getUser()

Version Twig

<p>Username: {{ app.user.username }}</p>

Aide de fournisseurs d'utilisateurs multiples

Chaque mécanisme d'authentification (par exemple l'authentification HTTP, formulaire de connexion, etc) utilise exactement une fournisseur de l'utilisateur, et utiliser le fournisseur de premier utilisateur déclarée par défaut. Mais que faire si vous voulez spécifier quelques utilisateurs via la configuration et le reste de vos utilisateurs dans la base de données? Ceci est possible par la création d'un nouveau fournisseur que les chaînes les deux ensemble:

Version Yaml

# app/config/security.yml
security:
    providers:
        chain_provider:
            providers: [in_memory, user_db]
        in_memory:
            users:
                foo: { password: test }
        user_db:
            entity: { class: Acme\UserBundle\Entity\User, property: username }

Version Xml

<!-- app/config/security.xml -->
<config>
    <provider name="chain_provider">
        <provider>in_memory</provider>
        <provider>user_db</provider>
    </provider>
    <provider name="in_memory">
        <user name="foo" password="test" />
    </provider>
    <provider name="user_db">
        <entity class="Acme\UserBundle\Entity\User" property="username" />
    </provider>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'providers' = > array(
        'chain_provider' = > array(
            'providers' = > array('in_memory', 'user_db'),
        ),
        'in_memory' = > array(
            'users' = > array(
                'foo' = > array('password' = > 'test'),
            ),
        ),
        'user_db' = > array(
            'entity' = > array('class' = > 'Acme\UserBundle\Entity\User', 'property' = > 'username'),
        ),
    ),
));

Maintenant, tous les mécanismes d'authentification utilise la chain_provider, puisque c'est la première visite. Le chain_provider sera, à son tour, essayez de charger l'utilisateur à la fois du in_memory et les fournisseurs de user_db.

Si vous n'avez pas de raisons pour séparer vos utilisateurs in_memory de vos utilisateurs user_db, vous pouvez accomplir ceci d'autant plus facilement en combinant les deux sources dans un seul fournisseur:

Version Yaml

# app/config/security.yml
security:
    providers:
        main_provider:
            users:
                foo: { password: test }
            entity: { class: Acme\UserBundle\Entity\User, property: username }

Version Xml

<!-- app/config/security.xml -->
<config>
    <provider name=="main_provider">
        <user name="foo" password="test" />
        <entity class="Acme\UserBundle\Entity\User" property="username" />
    </provider>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'providers' = > array(
        'main_provider' = > array(
            'users' = > array(
                'foo' = > array('password' = > 'test'),
            ),
            'entity' = > array('class' = > 'Acme\UserBundle\Entity\User', 'property' = > 'username'),
        ),
    ),
));

Vous pouvez également configurer les mécanismes d'authentification du pare-feu ou un individu d'utiliser un fournisseur spécifique. Encore une fois, sauf si un fournisseur est spécifié explicitement, le premier fournisseur est toujours utilisé:

Version Yaml

# app/config/security.yml
security:
    firewalls:
        secured_area:
            # ...
            provider: user_db
            http_basic:
                realm: "Secured Demo Area"
                provider: in_memory
            form_login: ~

Version Xml

<!-- app/config/security.xml -->
<config>
    <firewall name="secured_area" pattern="^/" provider="user_db">
        <!-- ... -->
        <http-basic realm="Secured Demo Area" provider="in_memory" />
        <form-login />
    </firewall>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' = > array(
        'secured_area' = > array(
            // ...
            'provider' = > 'user_db',
            'http_basic' = > array(
                // ...
                'provider' = > 'in_memory',
            ),
            'form_login' = > array(),
        ),
    ),
));

Dans cet exemple, si un utilisateur tente de se connecter via l'authentification HTTP, le système d'authentification utilise le fournisseur de l'utilisateur in_memory. Mais si l'utilisateur tente de se connecter via le formulaire de connexion, le fournisseur de user_db sera utilisé (puisque c'est la valeur par défaut du pare-feu dans son ensemble).

Pour plus d'informations sur fournisseur de l'utilisateur et la configuration de pare-feu, voir la référence de configuration de sécurité .

Rôles

L'idée d'un «rôle» est la clé du processus d'autorisation. Chaque utilisateur se voit attribuer un ensemble de rôles, puis chaque ressource nécessite un ou plusieurs rôles. Si l'utilisateur possède les rôles requis, l'accès est accordé. Sinon l'accès est refusé.

Les rôles sont assez simple, et sont essentiellement les chaînes que vous pouvez inventer et utiliser au besoin (si les rôles sont des objets à l'intérieur). Par exemple, si vous avez besoin pour commencer à limiter l'accès à la section admin blog de ​​votre site web, vous pouvez protéger cet article en utilisant un rôle ROLE_BLOG_ADMIN. Ce rôle n'a pas besoin d'être définie nulle part - il vous suffit de commencer à l'utiliser.

Tous les rôles doivent commencer par le préfixe ROLE_ à être géré par Symfony2. Si vous définissez vos propres rôles avec une classe Rôle dédié (plus avancé), ne pas utiliser le préfixe ROLE_.

Rôles hiérarchiques

Au lieu d'associer de nombreux rôles aux utilisateurs, vous pouvez définir des règles de succession rôle en créant une hiérarchie rôle:

Version Yaml

# app/config/security.yml
security:
    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

Version Xml

<!-- app/config/security.xml -->
<config>
    <role id="ROLE_ADMIN">ROLE_USER</role>
    <role id="ROLE_SUPER_ADMIN">ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH</role>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'role_hierarchy' = > array(
        'ROLE_ADMIN'       = > 'ROLE_USER',
        'ROLE_SUPER_ADMIN' = > array('ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH'),
    ),
));

Dans la configuration ci-dessus, les utilisateurs ayant un rôle ROLE_ADMIN aura également le rôle ROLE_USER. Le rôle ROLE_SUPER_ADMIN a ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH et ROLE_USER (hérité de ROLE_ADMIN).

Déconnexion

Habituellement, vous voulez également que vos utilisateurs soient en mesure de se déconnecter. Heureusement, le pare-feu peut gérer cela automatiquement pour vous lorsque vous activez le paramètre de déconnexion config:

Version Yaml

# app/config/security.yml
security:
    firewalls:
        secured_area:
            # ...
            logout:
                path:   /logout
                target: /
    # ...

Version Xml

<!-- app/config/security.xml -->
<config>
    <firewall name="secured_area" pattern="^/">
        <!-- ... -->
        <logout path="/logout" target="/" />
    </firewall>
    <!-- ... -->
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' = > array(
        'secured_area' = > array(
            // ...
            'logout' = > array('path' = > 'logout', 'target' = > '/'),
        ),
    ),
    // ...
));

Une fois que cela est configuré sous votre pare-feu, l'envoi d'un utilisateur de / déconnexion (ou ce que vous configurer le chemin de l'être), sera désélectionner authentifier l'utilisateur en cours. L'utilisateur sera alors envoyé à la page d'accueil (la valeur définie par le paramètre target). Tant le chemin d'accès et de configuration des paramètres par défaut cible de ce qui se spécifié ici. En d'autres termes, à moins que vous avez besoin de les personnaliser, vous pouvez les omettre complètement et de raccourcir votre configuration:

Version Yaml

logout: ~

Version Xml

<logout />

Version Php

'logout' = > array(),

Notez que vous n'aurez pas besoin de mettre en œuvre un contrôleur pour le / déconnexion URL que le pare-feu se charge de tout. Vous pouvez, cependant, veulent créer un itinéraire de sorte que vous pouvez l'utiliser pour générer l'URL:

Une fois que l'utilisateur a été déconnecté, il sera redirigé vers quelque soit le chemin est défini par le paramètre target ci-dessus (par exemple la page d'accueil). Pour plus d'informations sur la configuration de la déconnexion, voir la référence de configuration de sécurité .

Contrôle d'accès dans les templates

Si vous voulez vérifier si l'utilisateur courant a un rôle à l'intérieur d'un modèle, utilisez la fonction d'aide intégrée:

Version Twig

{% if is_granted('ROLE_ADMIN') %}
    <a href="...">Delete</a>
{% endif %}

Version Php

<?php if ($view['security']->isGranted('ROLE_ADMIN')): ?>
    <a href="...">Delete</a>
<?php endif; ?>

Si vous utilisez cette fonction et ne sont pas à une adresse URL où il ya un pare-feu actif, une exception sera levée. Encore une fois, c'est presque toujours une bonne idée d'avoir un pare-feu principal qui couvre toutes les URL (comme cela a été montré dans ce chapitre).

Contrôle d'accès dans les contrôleurs

Si vous voulez vérifier si l'utilisateur courant a un rôle dans votre contrôleur, utilisez la méthode isGranted du contexte de sécurité:

public function indexAction()
{
    // show different content to admin users
    if ($this->get('security.context')->isGranted('ROLE_ADMIN')) {
        // Load admin content here
    }
    // load other regular content here
}

Un pare-feu doit être active ou une exception sera levée lorsque la méthode est appelée isGranted. Voir la note ci-dessus à propos des modèles pour plus de détails.

Usurpation de l'identité d'un utilisateur

Parfois, il est utile de pouvoir passer d'un utilisateur à un autre sans avoir à déconnecter et vous reconnecter (par exemple lorsque vous effectuez le débogage ou d'essayer de comprendre un bug d'un utilisateur voit que vous ne pouvez pas reproduire). Ceci peut être facilement fait en activant le listener pare-feu switch_user:

Version Yaml

# app/config/security.yml
security:
    firewalls:
        main:
            # ...
            switch_user: true

Version Xml

<!-- app/config/security.xml -->
<config>
    <firewall>
        <!-- ... -->
        <switch-user />
    </firewall>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' = > array(
        'main'= > array(
            // ...
            'switch_user' = > true
        ),
    ),
));

Pour passer à un autre utilisateur, il suffit d'ajouter une chaîne de requête avec le paramètre _switch_user et le nom d'utilisateur que la valeur de l'URL en cours:

http://example.com/somewhere?_switch_user=thomas

Pour revenir à l'utilisateur d'origine, utilisez le nom d'utilisateur _exit spéciale:

http://example.com/somewhere?_switch_user=_exit

Bien sûr, cette fonction doit être mis à la disposition d'un petit groupe d'utilisateurs. Par défaut, l'accès est limité aux utilisateurs ayant le rôle ROLE_ALLOWED_TO_SWITCH. Le nom de ce rôle peut être modifié via la mise en rôle. Pour plus de sécurité, vous pouvez également changer le nom du paramètre de requête via le paramétrage:

Version Yaml

# app/config/security.yml
security:
    firewalls:
        main:
            // ...
            switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user }

Version Xml

<!-- app/config/security.xml -->
<config>
    <firewall>
        <!-- ... -->
        <switch-user role="ROLE_ADMIN" parameter="_want_to_be_this_user" />
    </firewall>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' = > array(
        'main'= > array(
            // ...
            'switch_user' = > array('role' = > 'ROLE_ADMIN', 'parameter' = > '_want_to_be_this_user'),
        ),
    ),
));

Authentification Stateless

Par défaut, Symfony2 repose sur un cookie (la session) à persister le contexte de sécurité de l'utilisateur. Mais si vous utilisez des certificats ou l'authentification HTTP, par exemple, la persistance n'est pas nécessaire que les informations d'identification sont disponibles pour chaque demande. Dans ce cas, et si vous n'avez pas besoin de stocker quoi que ce soit d'autre entre les demandes, vous pouvez activer l'authentification des apatrides (ce qui signifie que aucun cookie ne sera jamais créé par Symfony2):

Version Yaml

# app/config/security.yml
security:
    firewalls:
        main:
            http_basic: ~
            stateless:  true

Version Xml

<!-- app/config/security.xml -->
<config>
    <firewall stateless="true">
        <http-basic />
    </firewall>
</config>

Version Php

// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' => array(
        'main' => array('http_basic' => array(), 'stateless' => true),
    ),
));

Si vous utilisez un formulaire de connexion, Symfony2 créera un cookie, même si vous définissez un vrai apatride

Final Words

La sécurité peut être un problème profond et complexe à résoudre correctement dans votre application. Heureusement, le composant de sécurité de Symfony suit un modèle de sécurité éprouvé basé sur l'authentification et l'autorisation. D'authentification, ce qui arrive toujours en premier, est gérée par un pare-feu dont le travail consiste à déterminer l'identité de l'utilisateur à travers plusieurs méthodes différentes (par exemple l'authentification HTTP, formulaire de connexion, etc.) Dans le livre de cuisine, vous trouverez des exemples d'autres méthodes de gestion de l'authentification, y compris la façon de mettre en place un "remember me" La fonctionnalité des cookies.

Une fois qu'un utilisateur est authentifié, la couche d'autorisation peut déterminer si oui ou non l'utilisateur doit avoir accès à une ressource spécifique. Le plus souvent, les rôles sont appliqués à des URL, des classes ou les méthodes et si l'utilisateur actuel ne dispose pas de ce rôle, l'accès est refusé. La couche d'autorisation, cependant, est beaucoup plus profond, et suit un système de «vote» de sorte que plusieurs parties peuvent déterminer si l'utilisateur en cours devraient avoir accès à une ressource donnée. Pour en savoir plus à ce sujet et d'autres sujets dans le livre de cuisine. En savoir plus à partir du livre de recettes