Aller au contenu principal
PrestaConcept
Nos réalisations
  • Découvrez nos métiers
  • Développement web sur mesure

    Nous développons en méthode agile des back sous le framework PHP Symfony, des front en Angular.

  • Maintenance d'applications

    Maintien en condition opérationnelle de votre plateforme Symfony.

  • Expertise Symfony

    Coaching, formation, audit et conseil.

  • Hébergement et Infogérance

    Une expertise de l'hébergement depuis plus de 15 ans et l’infogérance de centaines de machines en production actuellement.

  • Découvrez Prestaconcept
  • PrestaConcept

    Notre histoire, nos convictions, notre vision... Découvrez ce qui nous anime !

  • L'équipe

    Plus de 15 ans minimum d'expérience sur Symfony.

  • Nos engagements RSE

    Une société engagée pour un numérique responsable.

  • Nos convictions

    Co-construction, transparence.. Les principes qui guident nos collaborations !

  • Nous rejoindre

    Envie de nous rejoindre ? Consultez nos offres !

  • Blog
    J'ai un projet Nous contacter
    J'ai un projet Nous contacter
    • Accueil
    • Blog
    • Tech
    • Bloquer la connexion simultanée à un même compte ? C'est possible !

    Blog

    Bloquer la connexion simultanée à un même compte ? C'est possible !

    redis sessions
    Maximilien Delangle
    Maximilien Delangle Développeur Symfony
    Publié le jeudi 8 septembre 2022

    Symfony nous fournit ce qu'il faut pour gérer un système d'authentification de base. Mais parfois il faut pouvoir aller au-delà. Ce sera le cas si vous souhaitez limiter la connexion à un utilisateur en simultanée.

    Bien sûr, vous n'aurez pas souvent ce genre de problématique. Mais si votre application a le besoin de métier de s'assurer qu'un seul utilisateur soit connecté à la fois, on vous demandera d'implémenter un tel système. C'est le cas si par exemple l'utilisateur de votre plateforme a un abonnement et qu'il faut vérifier la légitimité de sa connexion.

    Le système de connexion par défaut

    A priori, tout développeur a déjà pu avoir à mettre en oeuvre l'implémentation standard de la gestion d'utilisateurs de Symfony. On se retrouve le plus souvent avec un authenticator à base de quelques fonctions clefs ou, si vous êtes sur les versions les plus récentes, le nouveau système de badges.

    Mais comment bloquer la connexion simultanée à un même compte ? La théorie est plutôt simple, stocker la session de l'utilisateur dans un système de base de données afin d'avoir connaissance de l'existence d'une session pour pouvoir la remplacer par une nouvelle si nécessaire.

    Mise en oeuvre

    Pour cet exemple, nous avons choisi de travailler avec Redis pour stocker nos sessions. Il nous faudra donc dans un premier temps surcharger le système déjà en place afin de modifier le comportement du SessionHandler, Puis dans un second temps adapter la configuration pour appliquer notre nouvel handler.

    Surcharger RedisSessionHandler

    Le but de cette surcharge est de venir rajouter un peu de contexte sur la fonction doWrite pour cela on aura besoin du gestionnaire de token ainsi que de l'entity manager pour mettre à jour notre utilisateur. Il nous faudra gérer ensuite 2 cas :

    • L'utilisateur ne possède pas de session, dans ce cas-là on renseigne tout simplement l'id relatif à la session stockée dans Redis.
    • L'utilisateur a déjà une session, dans ce cas-là on détruit la session redis puis on renseigne le nouvel id de session de notre utilisateur.
    <?php
    
    namespace App\Session\Storage\Handler;
    
    use App\Entity\User;
    use Doctrine\ORM\EntityManagerInterface;
    use Redis;
    use Symfony\Component\Cache\Traits\RedisClusterProxy;
    use Symfony\Component\Cache\Traits\RedisProxy;
    use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler as NativeRedisSessionHandler
    use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
    
    class RedisSessionHandler extends NativeRedisSessionHandler
    {
    
        public function __construct(
            private \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis,
            private EntityManagerInterface $entityManager,
            private TokenStorageInterface $tokenStorage,
            private array $options = [])
        {
            $this->tokenStorage = $tokenStorage;
            $this->entityManager = $entityManager;
            $options['ttl'] = 43200;
            parent::__construct($redis, $options);
        }
    
        protected function doWrite($sessionId, $data): bool
        {
            $user = $this->tokenStorage->getToken()->getUser();
    
            if ($user instanceof User) {
                if($user->getSessionId() === null) {
                    $user->setSessionId($sessionId);
                    $this->entityManager->flush();
                }
                
                if($user->getSessionId() !== $sessionId) {
                    $this->doDestroy($user->getSessionId());
                    $user->setSessionId($sessionId);
                    $this->entityManager->flush();
                }
            }
    
            return parent::doWrite($sessionId, $data);
        }
    }
    

    Configuration

    Deux configurations sont nécessaires au bon fonctionnement de notre système.

    La première se trouve dans framework.yaml et a pour but de préciser le Handler à utiliser et donc pour notre cas, c'est ici qu'il faut renseigner l'utilisation de notre classe.

    framework:
         session:
              handler_id: App\Session\Storage\Handler\RedisSessionHandler
    

    La deuxième configuration, elle, permet le bon fonctionnement de notre SessionHandler.

    En effet, afin de fonctionner il faut bien lui renseigner l'instance de notre client Redis. De ce fait, direction le services.yaml. On aura donc :

    Redis:
         class: Redis
         calls:
              - connect:
                   - "%env(REDIS_HOST)%"
                   - "%env(int:REDIS_PORT)%"
     
    App\Session\Storage\Handler\RedisSessionHandler:
         arguments:
              - '@Redis'
    

    Pour aller plus loin

    Bien sûr, dans notre exemple assez basique, nous faisons le choix de supprimer purement et simplement la session précédente de l'utilisateur. Mais nous pouvons imaginer avoir d'autres actions comme afficher un message d'avertissement et de confirmation à l'utilisateur, ou envoyer une notification à un administrateur l'avertissant de connexions simultanées. Sans compter le fait que vous n'êtes pas obligé d'utiliser Redis, un autre stockage en base sera envisageable pour pouvoir les manipuler. L'essentiel est de pouvoir surcharger l'implémentation standard de Symfony pour ajouter la fonctionnalité que vous voulez.

    Une question, un projet ? Planifiez un échange avec nous !

    Que vous ayez une idée encore floue, un projet bien défini ou simplement envie d'en savoir plus sur notre façon de travailler, on adore ces premiers échanges. Choisissez le créneau qui vous arrange, et on prend le temps de discuter ensemble de ce qui vous amène.

    Choisissez votre date
    PrestaConcept - Groupe Agile Invest
    5, imp. Morel, 69003 Lyon +33 (0)4 78 54 45 45
    Suivez-nous
    Ecoindex B

    Ce site internet est un site basse consommation. En savoir plus sur l'Ecoindex

    Nos réalisations

  • Logiciel de mise en conformité réglementaire
  • Application de suivi de production des centrales éoliennes
  • Outil d'aide à la décision
  • Portail client
  • Nos métiers

  • Développement sur-mesure
  • Reprise d'application Symfony
  • Expertise Symfony
  • Hébergement & Infogérance
  • Qui sommes-nous

  • PrestaConcept
  • Groupe Agile Invest
  • L'équipe
  • Engagement RSE
  • Blog

  • Tech
  • Méthodologie
  • PrestaConcept
  • RSE
  • © 2026 PrestaConcept
    Mentions légales Politique de confidentialité 🍪
    Retour en haut de page