symfony - Symfony 4.4.2 - 带有 TokenStorageInterface 的 EventListener 使调试栏显示“加载 Web 调试工具栏时发生错误”。
问题描述
我刚刚将一个应用程序从 Symfony 4.3.9 升级到 4.4.2。之后,我的调试栏无法正常工作并显示“加载 Web 调试工具栏时发生错误。” 经过长时间的调查,我发现这是由于 security.authentication.failure 事件上的 EventListener 造成的。评论 onAuthenticationFailure 方法内容什么也没做,经过一番调查,它在从标签和构造函数中删除 TokenStorageInterface 时起作用......但我需要它。
有任何想法吗?
这是代码:
服务.yaml
App\EventListener\LoginListener:
arguments: ["@doctrine", "@security.token_storage", "@router", "@event_dispatcher"]
tags:
- { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure }
登录监听器.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();
}
}
}
谢谢 :)
---EDIT--- 事实上,听众是另一个人的编辑。它不需要 TokenStorage 但我会在不久的将来遇到问题:
<?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'));
}
}
解决方案
推荐阅读
- reactjs - h如何在react中操作数据
- python - matplotlib 中的渐变填充和颜色过渡
- uml - 如何在 UML 中表示作为多维数组的属性?
- python-3.x - Python 3 中不允许使用 urllib2 的方法
- php - Apache:错误 AH00557 和 AH00558 不会消失,PHP 无法正常工作
- c - 将结构指针初始化为空
- ajax - CodeIgniter 上的 ajax 403 错误
- python - IntelliJ Python intellisense 无法识别使用 add2virtualenv 添加到 virtualenvwrapper 的库
- c# - C# UWP“订阅值更改”
- python - Keras - 多输出模型的准确性不起作用