De manière générale, un backoffice se sécurise rapidement avec FosUserBundle, et c’est très bien ainsi, car on ne veut pas s’embêter à recoder tout un système d’authentification classique (login/rappel de mot de passe, changement de mot de passe etc)
Mais, de manière générale, côté front, il est courant de vouloir à la fois avoir une table différente de FosUser, et avoir une authentification complètement personnalisée (si vous utilisez FosUserBundle, il faudra surcharger les contrôleurs pour pouvoir faire ce que vous voulez)
Dans une série de précédents articles, nous avons vus comment créer une authentification de A à Z sans FosUserBundle.
J’ai repris les sources dans un nouveau projet (https://github.com/jpsymfony/REST-BEHAT) en combinant FosUserBundle pour le backoffice et une authentification personnalisée pour le front.
Comment mettre en place les providers et firewalls?
Comme à l’accoutumée lorsqu’on veut hériter d’un bundle, j’en ai créé un que j’ai appelé BackUserBundle, et qui étend FosUserBundle.
Dans le CoreBundle, j’ai placé les entités et les repositories. Les formTypes se trouvent dans les bundles où ils sont appelés (ici BlogBundle)
Voici comment se présente le fichier security.yml:
security: encoders: FOS\UserBundle\Model\UserInterface: sha512 App\CoreBundle\Entity\User: sha512 role_hierarchy: ROLE_ADMIN: ROLE_USER ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] providers: fos_userbundle: id: fos_user.user_provider.username database_users: entity: { class: AppCoreBundle:User, property: username } firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false bo: pattern: ^/admin form_login: provider: fos_userbundle csrf_provider: form.csrf_provider login_path: /admin/login check_path: /admin/login_check logout: path: /admin/logout target: / anonymous: ~ remember_me: key: "%secret%" lifetime: 31536000 # 365 jours en secondes path: / domain: ~ # Prend la valeur par défaut du domaine courant depuis $_SERVER fo: # this firewall applies to all URLs pattern: ^/ # but the firewall does not require login on every page # denying access is done in access_control or in your controllers anonymous: true # This allows the user to login by submitting a username and password # Reference: http://symfony.com/doc/current/cookbook/security/form_login_setup.html form_login: provider: database_users # The route name that the login form submits to check_path: security_login_check # The name of the route where the login form lives # When the user tries to access a protected page, they are redirected here login_path: security_login_form # Secure the login form against CSRF # Reference: http://symfony.com/doc/current/cookbook/security/csrf_in_login_form.html csrf_provider: security.csrf.token_manager default_target_path: user_dashboard always_use_default_target_path: true logout: # The route name the user can go to in order to logout path: security_logout # The name of the route to redirect to after logging out target: homepage access_control: - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/register, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin, role: ROLE_ADMIN } - { path: ^/account/register, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/account, roles: IS_AUTHENTICATED_FULLY } - { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY }
Comme vous pouvez le voir, il y a deux encoders, un faisant appel à Fos, l’autre étant ma classe de User.
Concernant les providers, je déclare les deux.
Côté firewalls, j’ai l’habituel dev, puis le backoffice, et enfin le frontoffice. Petite subtilité, remarquez que pour chaque firewall, j’ai indiqué quel provider était utilisé, sinon Symfony ne sait pas lequel choisir et prend le premier qu’on lui donne (ici celui de Fos, ce qui revient à être refoulé à l’authentification)
Et enfin, côté access_control, uniquement du classique, puisque je sécurise l’interface admin, sécurise l’espace authentifié d’un utilisateur et autorise le reste en anonymous.
Si vous désirez tester l’application, n’oubliez pas de lancer la commande php app/console doctrine:fixtures:load pour avoir des users en base (cf le détail des fixtures dans CoreBundle/DataFixtures)