Symfony安全注销未清除RememberMe令牌

时间:2017-12-21 20:58:08

标签: php symfony symfony-security

将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 \元器件\安全\ HTTP \防火墙\ ChannelListener   Symfony的\分量\安全\ HTTP \防火墙\ ContextListener   的Symfony \组件\安全\ HTTP \防火墙\ LogoutListener

     

的Symfony \元器件\安全\ HTTP \防火墙\ UsernamePasswordFormAuthenticationListener   的Symfony \组件\安全\ HTTP \防火墙\ RememberMeListener

     

的Symfony \元器件\安全\ HTTP \防火墙\ AnonymousAuthenticationListener   的Symfony \组件\安全\ HTTP \防火墙\ AccessListener

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

2 个答案:

答案 0 :(得分:0)

自2013年以来,它看起来是一个众所周知的问题!

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

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

答案 1 :(得分: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);
    }
}