Aller au contenu

Entête partagé : identité, déconnexion et bascule

Cette page explique pourquoi Kirexo affiche un même entête en haut de la page d'accueil publique et des deux espaces (utilisateur et admin), ce qu'il montre selon l'état de connexion et le type de compte, et pourquoi la présence du bouton de bascule n'est qu'une commodité d'affichage — l'autorisation réelle restant portée par le Voter CanSwitchSpaceVoter. Pour le parcours pas-à-pas de la bascule côté utilisateur, voir le how-to Basculer entre l'espace administrateur et l'espace utilisateur.

Un entête, trois contextes

Trois pages affichent le même entête, alors qu'elles appartiennent à des contextes très différents :

  • la page d'accueil publique, accessible à tout le monde (anonyme ou connecté) ;
  • l'espace utilisateur (/u), réservé aux comptes authentifiés sur le firewall user ;
  • l'espace d'administration (/admin), réservé aux comptes authentifiés sur le firewall admin.

Plutôt que de dupliquer trois barres de navigation, Kirexo factorise cet entête dans un unique composant Twig : src/Twig/Components/Header.php et son gabarit templates/components/Header.html.twig. Il est intégré dans les trois layouts via une seule balise — templates/base_user.html.twig, templates/base_admin.html.twig et templates/home/index.html.twig — sous la forme <twig:Header space="…" />.

Le composant ne porte aucun état interactif : il ne fait qu'afficher des liens et des formulaires POST. C'est donc un composant Twig simple, pas un Live Component — conformément à la règle « pas de Live Component si un composant statique suffit ».

La prop space pilote tout l'affichage

Le composant reçoit une unique propriété, space, qui vaut public, user ou admin selon le layout qui l'instancie. Cette valeur détermine :

  • la brand affichée — « Kirexo » partout, suffixée « — Admin » dans l'espace d'administration, et pointant toujours vers l'accueil (app_home) ;
  • la route de déconnexion ciblée (app_admin_logout dans l'espace admin, app_logout ailleurs) ;
  • le sens de la bascule pour un compte mixte (vers l'admin depuis /u, vers l'utilisateur depuis /admin) ;
  • l'affichage, ou non, du lien « Se connecter » (réservé à l'accueil public anonyme).

space est une donnée d'affichage choisie par le layout, jamais une donnée de sécurité : ce n'est pas elle qui protège les espaces. Le cloisonnement réel reste assuré par les deux firewalls et access_control (voir Architecture des firewalls).

Ce qui s'affiche selon l'état

L'entête combine deux dimensions : suis-je connecté ? et, si oui, mon compte est-il mixte ?. Le tableau résume les cas.

Contexte État du compte Entête affiché
Accueil public (space="public") Anonyme Brand + lien « Se connecter » (vers app_login)
Accueil public (space="public") Connecté Brand + email du compte. Ni lien de connexion, ni déconnexion, ni bascule
Espace user (space="user") Connecté, non mixte Brand + email + « Se déconnecter »
Espace user (space="user") Connecté, mixte Brand + email + « Basculer vers l'espace admin » + « Se déconnecter »
Espace admin (space="admin") Connecté, non mixte Brand « Kirexo — Admin » + email + « Se déconnecter »
Espace admin (space="admin") Connecté, mixte Brand « Kirexo — Admin » + email + « Basculer vers l'espace utilisateur » + « Se déconnecter »

Quelques points méritent d'être soulignés.

L'accueil public ne propose jamais le login admin

Sur la page d'accueil, un visiteur anonyme ne voit qu'un seul lien de connexion : « Se connecter », qui mène vers la page de login utilisateur (app_login). L'entête ne propose jamais de lien vers /admin/login. C'est cohérent avec le masquage 404 de l'admin : l'espace d'administration ne s'annonce pas aux visiteurs publics. Un administrateur connaît son URL de login ; elle n'a pas à être exposée depuis l'accueil.

Sur l'accueil, un compte connecté ne voit ni déconnexion ni bascule

Si un compte est connecté lorsqu'il consulte l'accueil public, l'entête affiche son email mais ne propose ni déconnexion ni bascule. La raison : l'accueil n'appartient à aucun firewall d'espace. La déconnexion vise une session de firewall précise (user ou admin), et la bascule transite d'un espace vers l'autre — deux actions qui n'ont de sens que depuis un espace. L'entête de l'accueil se contente donc de signaler « tu es connecté », sans offrir d'action contextuelle.

La déconnexion suit le firewall de l'espace

Chaque espace possède sa propre session de firewall. L'entête cible donc la bonne route de logout selon space : app_admin_logout quand space="admin", app_logout sinon. Se déconnecter de l'espace admin ne déconnecte pas une éventuelle session utilisateur, et inversement — c'est une conséquence directe de la séparation en deux firewalls.

Le bouton de bascule n'apparaît que pour les comptes mixtes

Le bouton « Basculer vers l'espace … » n'est rendu que si le compte est mixte — c'est-à-dire porteur à la fois de ROLE_USER et ROLE_ADMIN. Pour un compte qui n'a qu'un seul de ces rôles, basculer n'aurait pas de cible légitime : le bouton est donc absent. Le sens de la bascule découle de space : depuis user, on bascule vers admin ; depuis admin, vers user ; depuis public, jamais (l'accueil n'est pas un espace de départ).

La visibilité du bouton est une commodité, pas une autorisation

C'est le point conceptuel important de cette page.

Le composant expose une méthode getSwitchTarget() qui renvoie l'espace de destination ('admin', 'user') ou null. Le gabarit n'affiche le formulaire de bascule que lorsque cette méthode renvoie une cible. Cette méthode décide en lisant les rôles du compte courant (isMixed()) et l'espace courant.

Cette logique d'affichage ne fait pas autorité. Elle sert uniquement à éviter de présenter un bouton qui mènerait à un échec — une question d'ergonomie, pas de sécurité. L'autorisation réelle de basculer est portée ailleurs, en un seul endroit faisant foi : le Voter src/Security/Voter/CanSwitchSpaceVoter.php, qui n'accorde l'attribut CAN_SWITCH_SPACE qu'aux comptes mixtes. Ce Voter garde les deux controllers de bascule via #[IsGranted(CanSwitchSpaceVoter::CAN_SWITCH_SPACE)] (src/Controller/AppSwitchToAdminController.php et src/Controller/AppSwitchToUserController.php).

Autrement dit, même si l'entête affichait le bouton à tort, ou si un compte forgeait manuellement un POST vers /switch ou /admin/switch, la requête serait rejetée par le Voter avant toute génération de jeton. Le formulaire de bascule porte d'ailleurs son propre jeton CSRF (switch_space), et le mécanisme complet — jeton signé à usage unique, vérification de rôle à la consommation — est détaillé dans Mécanisme de bascule entre espaces.

Pourquoi dédoubler le contrôle (affichage + Voter) ?

La condition d'affichage de l'entête (isMixed()) et le Voter CanSwitchSpaceVoter répondent à la même question — « ce compte peut-il basculer ? » — mais ne jouent pas le même rôle. Le composant améliore l'expérience (ne pas montrer un bouton qui échouerait) ; le Voter assure la sécurité (refuser toute bascule illégitime, quel que soit l'affichage). Si les deux divergeaient, c'est toujours le Voter qui tranche : il est le seul à faire autorité. C'est une application directe de la règle du projet « aucune décision d'autorisation inline » — la décision vit dans un Voter, pas dans un gabarit.

Voir aussi