首页 文章

Symfony安全注销未清除RememberMe令牌

提问于
浏览
2

像这样使用Symfony 4和 security.yaml

encoders:
  App\Entity\User: sha256
providers:
    public_users:
      entity:
        class: App\Entity\User
        property: email
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        pattern: ^/

        anonymous: ~

        form_login:
          login_path: login
          remember_me:    true

        remember_me:
            secret: "%kernel.secret%"
            name:  relevea_remember_me
            lifetime: 864000
            always_remember_me: false
            remember_me_parameter: user_login[stayConnected]

        logout:
            path: logout
            target: /about
            invalidate_session: false

access_control:
  - { path: ^/auth, roles: IS_AUTHENTICATED_ANONYMOUSLY }

logout 操作未清除rememberMe令牌 .

我可以看到 LogoutListenerhttps://github.com/symfony/security/blob/master/Http/Firewall/LogoutListener.php)在 RememberMeListenerhttps://github.com/symfony/security/blob/master/Http/Firewall/RememberMeListener.php)之后被调用,因此对于LogoutListener,令牌为空并且没有清除任何内容:/

来自 TraceableFirewallListener 的监听器列表:

Symfony \ Component \ Security \ Http \ Firewall \ ChannelListener Symfony \ Component \ Security \ Http \ Firewall \ ContextListener Symfony \ Component \ Security \ Http \ Firewall \ LogoutListener Symfony \ Component \ Security \ Http \ Firewall \ UsernamePasswordFormAuthenticationListener Symfony \ Component \ Security \ Http \ Firewall \ RememberMeListener Symfony \ Component \ Security \ Http \ Firewall \ AnonymousAuthenticationListener Symfony \ Component \ Security \ Http \ Firewall \ AccessListener

为什么退出监听器先于其他人?

2 回答

  • 0

    自2013年以来,它看起来是个已知问题!

    https://github.com/symfony/symfony/issues/7104

    所以基本上,你不能从RememberMe令牌注销:/

  • 0

    您可以覆盖防火墙侦听器以调用logout侦听器,如下所示

    security.firewall:
        class: AppBundle\Security\FirewallListener
        arguments:
           - '@security.firewall.map'
           - '@event_dispatcher'
           - '@security.logout_url_generator'
        tags:
           - { name: kernel.event_subscriber }
    
    
    use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
    use Symfony\Component\EventDispatcher\EventDispatcherInterface;
    use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
    use Symfony\Component\Security\Http\Firewall;
    use Symfony\Component\Security\Http\Firewall\LogoutListener;
    use Symfony\Component\Security\Http\FirewallMapInterface;
    use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
    
    class FirewallListener extends Firewall
    {
        private $map;
        private $exceptionListeners;
        private $logoutUrlGenerator;
        private $dispatcher;
    
        public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher, LogoutUrlGenerator $logoutUrlGenerator)
        {
            $this->map = $map;
            $this->dispatcher = $dispatcher;
            $this->exceptionListeners = new \SplObjectStorage();
            $this->logoutUrlGenerator = $logoutUrlGenerator;
    
            parent::__construct($map, $dispatcher);
        }
    
        /**
         * {@inheritdoc}
         */
        public function onKernelRequest(GetResponseEvent $event)
        {
            if (!$event->isMasterRequest()) {
                return;
            }
            if ($this->map instanceof FirewallMap && $config = $this->map->getFirewallConfig($event->getRequest())) {
                $this->logoutUrlGenerator->setCurrentFirewall($config->getName(), $config->getContext());
            }
    
            // register listeners for this firewall
            list($listeners, $exceptionListener) = $this->map->getListeners($event->getRequest());
            if (null !== $exceptionListener) {
                $this->exceptionListeners[$event->getRequest()] = $exceptionListener;
                $exceptionListener->register($this->dispatcher);
            }
    
            // initiate the listener chain
            $logoutListener = null;
            foreach ($listeners as $listener) {
                if ($listener instanceof LogoutListener) {
                    $logoutListener = $listener;
                    continue;
                }
    
                $listener->handle($event);
    
                if ($event->hasResponse()) {
                    break;
                }
            }
    
            if ($logoutListener) {
                $logoutListener->handle($event);
            }
        }
    
        /**
         * {@inheritdoc}
         */
        public function onKernelFinishRequest(FinishRequestEvent $event)
        {
            if ($event->isMasterRequest()) {
                $this->logoutUrlGenerator->setCurrentFirewall(null);
            }
    
            parent::onKernelFinishRequest($event);
        }
    }
    

相关问题