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)

Commentaires