dongzhan2461 2016-11-01 08:07
浏览 66
已采纳

在Symfony的FOSUserBundle中检测重复登录

i'm using the FOSUserBundle in my Symfony project and i need to remove duplicate logins. If a user logs in from a different system, I want his/her other session to be disconnected.

Can you please help me on my way?

  • 写回答

2条回答 默认 最新

  • doujuyang1764 2016-11-01 09:38
    关注

    The easy way:

    Map an activeSessionId field to your User class:

    /**
     * @ORM\Entity
     * @ORM\Table(name="fos_user")
     */
    class User extends BaseUser
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;
    
        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $activeSessionId;
    
        public function loginWithSessId($sessionId)
        {
            $this->activeSessionId = $sessionId;
        }
    
        public function logout()
        {
            $this->activeSessionId = null;
        }
    
        public function getActiveSessId()
        {
            return $this->activeSessionId;
        }
    }
    

    Then listen to the security.interactive_login event that will be fired every time the user log in, and save a reference of the session id together with the user:

    namespace AppBundle\Security;
    
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
    use Symfony\Component\Security\Http\SecurityEvents;
    use FOS\UserBundle\Model\UserManagerInterface;
    
    class LoginListener implements EventSubscriberInterface
    {
        private $userManager;
    
        public function __construct(UserManagerInterface $userManager)
        {
            $this->userManager = $userManager;
        }
    
        public static function getSubscribedEvents()
        {
            return array(
                SecurityEvents::INTERACTIVE_LOGIN => 'onSecurityInteractiveLogin',
            );
        }
    
        public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
        {
            $user = $event->getAuthenticationToken()->getUser();
            $session = $event->getRequest()->getSession();
    
            $user->loginWithSessId($session->getId());
            $this->userManager->updateUser($user);
        }
    }
    

    You can then register the listener with:

    <service id="app_bundle.security.login_listener" class="AppBundle\Security\LoginListener">
        <argument type="service" id="fos_user.user_manager"/>
        <tag name="kernel.event_subscriber" />
    </service>
    

    or

    # app/config/services.yml
    services:
        app_bundle.security.login_listener:
            class: AppBundle\Security\LoginListener
            arguments: ['@fos_user.user_manager']
            tags:
                - { name: kernel.event_subscriber }
    

    Now that your User entity know which session is the last one, you can creare a listener to the security.authentication.success event, and check if the current session id match with the last active one. If it doesn't, then it's not an active session anymore.

    namespace AppBundle\Security;
    
    use Symfony\Component\Security\Core\AuthenticationEvents;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\Security\Core\Event\AuthenticationEvent;
    use Symfony\Component\HttpFoundation\RequestStack;
    use FOS\UserBundle\Model\UserManagerInterface;
    
    class AuthenticationListener implements EventSubscriberInterface
    {
        private $requestStack;
        private $userManager;
    
        public function __construct(RequestStack $requestStack, UserManagerInterface $userManager)
        {
            $this->requestStack = $requestStack;
            $this->userManager = $userManager;
        }
    
        public static function getSubscribedEvents()
        {
            return array(
                AuthenticationEvents::AUTHENTICATION_SUCCESS => 'onAuthenticationSuccess',
            );
        }
    
        public function onAuthenticationSuccess(AuthenticationEvent $event)
        {
            $token = $event->getAuthenticationToken();
            $sessionId = $this->requestStack->getMasterRequest()->getSession()->getId();
            $activeSessId = $token->getUser()->getActiveSessId();
    
            if ($activeSessId && $sessionId !== $activeSessId) {
                $token->setAuthenticated(false); // Sets the authenticated flag.
            }
        }
    }
    

    Finally:

    <service id="app_bundle.security.auth_listener" class="AppBundle\Security\AuthenticationListener">
        <argument type="service" id="request_stack"/>
        <argument type="service" id="fos_user.user_manager"/>
        <tag name="kernel.event_subscriber" />
    </service>
    

    or

    # app/config/services.yml
    services:
        app_bundle.security.auth_listener:
            class: AppBundle\Security\AuthenticationListener
            arguments: ['@request_stack', '@fos_user.user_manager']
            tags:
                - { name: kernel.event_subscriber }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥50 求解vmware的网络模式问题 别拿AI回答
  • ¥24 EFS加密后,在同一台电脑解密出错,证书界面找不到对应指纹的证书,未备份证书,求在原电脑解密的方法,可行即采纳
  • ¥15 springboot 3.0 实现Security 6.x版本集成
  • ¥15 PHP-8.1 镜像无法用dockerfile里的CMD命令启动 只能进入容器启动,如何解决?(操作系统-ubuntu)
  • ¥30 请帮我解决一下下面六个代码
  • ¥15 关于资源监视工具的e-care有知道的嘛
  • ¥35 MIMO天线稀疏阵列排布问题
  • ¥60 用visual studio编写程序,利用间接平差求解水准网
  • ¥15 Llama如何调用shell或者Python
  • ¥20 谁能帮我挨个解读这个php语言编的代码什么意思?