Symfony 4.4.2-带有TokenStorageInterface的EventListener使调试栏显示;加载web调试工具栏时出错。”;

Symfony 4.4.2-带有TokenStorageInterface的EventListener使调试栏显示;加载web调试工具栏时出错。”;,symfony,symfony4,Symfony,Symfony4,我刚刚将一个应用程序从Symfony 4.3.9升级到4.4.2。之后,调试栏不工作,并显示“加载web调试工具栏时出错” 经过长时间的调查,我发现这是由于security.authentication.failure事件上的EventListener造成的。 注释onAuthenticationFailure方法内容没有任何作用,经过一些调查后,它在从标记和构造函数中删除TokenStorageInterface时起作用。。。但我需要它 有什么想法吗 代码如下: 服务.亚马尔 App\

我刚刚将一个应用程序从Symfony 4.3.9升级到4.4.2。之后,调试栏不工作,并显示“加载web调试工具栏时出错” 经过长时间的调查,我发现这是由于security.authentication.failure事件上的EventListener造成的。 注释onAuthenticationFailure方法内容没有任何作用,经过一些调查后,它在从标记和构造函数中删除TokenStorageInterface时起作用。。。但我需要它

有什么想法吗

代码如下:

服务.亚马尔

    App\EventListener\LoginListener:
    arguments: ["@doctrine", "@security.token_storage", "@router", "@event_dispatcher"]
    tags:
        - { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure }
LoginListener.php

<?php

namespace App\EventListener;

use App\Entity\AdminUser;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;

/**
 * Class LoginListener
 * Listens to user log in events (failure, interactive log in) to provide additionnal security measures
 *
 * @package App\EventListener
 */
final class LoginListener
{
    protected $doctrine;
    protected $request;
    protected $tokenStorage;
    protected $router;
    protected $dispatcher;

    /**
     * Login constructor.
     *
     * @param Registry                 $doctrine
     * @param TokenStorageInterface    $tokenStorage
     * @param RouterInterface          $router
     * @param EventDispatcherInterface $dispatcher
     */
    public function __construct(
        Registry $doctrine,
        TokenStorageInterface $tokenStorage,
        RouterInterface $router,
        EventDispatcherInterface $dispatcher
    ) {
        $this->doctrine = $doctrine;
        $this->tokenStorage = $tokenStorage;
        $this->router = $router;
        $this->dispatcher = $dispatcher;
    }

    /**
     * @param AuthenticationFailureEvent $event
     * @throws ORMException
     * @throws OptimisticLockException
     */
    public function onAuthenticationFailure(AuthenticationFailureEvent $event)
    {
        /** @var EntityManager $em */
        $em = $this->doctrine->getManager();
        $username = $event->getAuthenticationToken()->getUsername();
        /** @var AdminUser $user */
        $user = $em->getRepository(AdminUser::class)->findOneBy(['username' => $username]);
        if ($user instanceof AdminUser) {
            $user->addFailedLogin();
            if ($user->getFailedLogin() == 5) {
                $user->setLocked(1);
            }
            $em->persist($user);
            $em->flush();
        }
    }
}

我觉得你做了一个登录验证人所做的工作,但是在错误的地方——当技术上成功登录时,你试图在事后使其失败。在上一个代码块中,您还使用了TokenStorage而不是TokenStorageInterface(这并不是说它有什么区别,这很奇怪)。您的“延迟注销”尝试可能通过自定义用户加载查询得到更好的处理,在这种情况下,您可以执行所有检查,而不返回用户。但是,当用户以非交互方式进行身份验证时,这种方法也会阻止用户。。。
<?php

namespace App\XXXBundle\EventListener;

use App\XXXBundle\Entity\AdminUser;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\ORM\EntityManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

/**
 * Class Login
 * Listens to user log in events (failure, interactive log in) to provide additionnal security measures
 *
 * @package App\XXXBundle\EventListener
 */
class Login
{
    protected $doctrine;
    protected $request;
    protected $tokenStorage;
    protected $router;
    protected $dispatcher;

    /**
     * Login constructor.
     *
     * @param Registry                 $doctrine
     * @param TokenStorage             $tokenStorage
     * @param RouterInterface          $router
     * @param EventDispatcherInterface $dispatcher
     */
    public function __construct(
        Registry $doctrine,
        TokenStorage $tokenStorage,
        RouterInterface $router,
        EventDispatcherInterface $dispatcher
    ) {
        $this->doctrine = $doctrine;
        $this->tokenStorage = $tokenStorage;
        $this->router = $router;
        $this->dispatcher = $dispatcher;
    }

    /**
     * @param AuthenticationFailureEvent $event
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function onAuthenticationFailure(AuthenticationFailureEvent $event)
    {
        /** @var EntityManager $em */
        $em = $this->doctrine->getManager();
        $userName = $event->getAuthenticationToken()->getUsername();
        /** @var AdminUser $user */
        $user = $em->getRepository(AdminUser::class)->findOneByUsername($userName);
        if ($user instanceof AdvancedUserInterface) {
            $user->addFailedLogin();
            if ($user->getFailedLogin() == 5) {
                $user->setLocked(1);
            }
            $em->persist($user);
            $em->flush();
        }
    }

    /**
     * @param InteractiveLoginEvent $event
     * @throws \Exception
     */
    public function onInteractiveLogin(InteractiveLoginEvent $event)
    {
        $user = $event->getAuthenticationToken()->getUser();
        if ($user instanceof AdvancedUserInterface) {
            $em = $this->doctrine->getManager();
            if ($user->getLocked()) {
                $this->tokenStorage->setToken(null);
                throw new CustomUserMessageAuthenticationException('Compte verrouillé.');
            }
            if ($user->getExpiresAt() && $user->getExpiresAt() <= new \DateTime()) {
                $user->setIsActive(0);
                $em->persist($user);
                $em->flush();
                $this->tokenStorage->setToken(null);
                throw new CustomUserMessageAuthenticationException('Compte expiré.');
            }
            if ($user->getCredentialsExpireAt() && $user->getCredentialsExpireAt() <= new \DateTime()) {
                $this->dispatcher->addListener(KernelEvents::RESPONSE, [$this, 'redirectToCredentialsChange']);
            }
            $user->setLastLogin(new \DateTime());
            $user->setFailedLogin(0);
            $em->persist($user);
            $em->flush();
        }

    }

    public function redirectToCredentialsChange(ResponseEvent $event)
    {
        $event->getResponse()->headers->set('Location', $this->router->generate('admin_security_changecredentials'));
    }
}