PrestaConcept
Nos réalisations
Nos métiers
  • 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.

  • Qui sommes nous
  • 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 Menu
    • 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.

    Blog

    Pour continuer votre lecture ...

    Tech

    5 Design Patterns que vous avez utilisé au quotidien avec Symfony

    Par Maximilien Delangle 05/07/2024

    Lorsque nous développons avec Symfony, nous utilisons souvent des design patterns sans même nous en rendre compte.
    Dans cet article, nous présenterons cinq design patterns issus de Symfony, et illustrés de leur code source.

    Lire la suite
    Tech

    Optimisation du développement web avec de l'IA (Chat GPT, Copilot...)

    Par Maximilien Delangle 21/02/2024

    L'avènement de l'intelligence artificielle (IA) dans le secteur de l'information et de la technologie (IT) a déclenché une révolution, changeant radicalement la manière dont nous interagissons avec les machines, concevons les logiciels et abordons le développement web. Parmi les avancées les plus si...

    Lire la suite
    Tech

    AFUPDay 2023: Des sujets bien interessants !

    Par Maximilien Delangle 01/06/2023

    L'AFUP Day 2023, c'était le 12 mai 2023 en simultanée à Lille et à Lyon. Sponsor des éditions lyonnaises et lilloises, nous avons eu le plaisir de participer à celle de Lyon et vous proposons un petit retour sur cette journée.

    Lire la suite

    Vous avez un projet Laravel ?

    Nous sommes spécialisés en Symfony, et grâce à Web^ID, l’agence sœur du groupe Agile Invest, nous couvrons aussi toute l’expertise Laravel.

    Découvrir Web^ID

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

    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
  • © 2025 PrestaConcept
    Mentions légales Politique de confidentialité 🍪
    Retour en haut de page