UserChecker - использовать менеджер сущностей

Мой сайт работает под управлением Symfony 3.4, и я создал собственную систему пользователей. Моя сущность User содержит поле Datetime 'lastLogin', и я не могу найти решение для его обновления каждый раз, когда пользователь входит в систему.

Я создал пользовательский UserChecker, а затем попытался обновить поле в нем:

<?php

namespace CoreBundle\Security;

use CoreBundle\Entity\User as AppUser;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class UserChecker implements UserCheckerInterface
{
    public function checkPreAuth(UserInterface $user)
    {
        if (!$user instanceof AppUser) {
            return;
        }
        if ( $user->getDeleted() || !$user->getEnabled()  )
        {
            throw new AuthenticationException();
        }
        else
        {
            // BELOW IS WHAT I TRY, BUT FAIL.
            $entityManager = $this->get('doctrine')->getManager();
            $user->setLastLogin(new \DateTime());
            $entityManager->persist($user);
            $entityManager->flush();
        }
    }

    public function checkPostAuth(UserInterface $user)
    {
        if (!$user instanceof AppUser) {
            return;
        }
    }
}

Но это не работает. Может быть, я не могу использовать менеджер сущностей доктрины в этом файле?

Если я использую $this->get('doctrine')->getManager(); Я получил:

Неустранимая ошибка: вызов неопределенного метода CoreBundle\Security\UserChecker::get()

1 ответ

Решение

Не знаю, почему @doncallisto удалил свой пост. Это было (ИМХО) правильное.

Взгляните на http://symfony.com/doc/current/components/security/authentication.html

Итак, у вас есть несколько вариантов.

  • SecurityEvents::INTERACTIVE_LOGIN - срабатывает каждый раз, когда пользователь заполняет форму входа и отправляет учетные данные. Будет работать, но выне будете получать обновления last_login, если у вас есть remember_me печенье или подобное

  • AuthenticationEvents::AUTHENTICATION_SUCCESS - срабатывает каждый раз(каждый запрос), когда аутентификация прошла успешно. Это означает, что ваш last_login будет обновляться каждый раз при каждом запросе, если пользователь не вышел из системы

так что вам нужен EventSubscriber. Посмотрите на эту статью. https://thisdata.com/blog/subscribing-to-symfonys-security-events/

Возможно, вам понадобится упрощенная версия.

public static function getSubscribedEvents()
{
        return array(
            // AuthenticationEvents::AUTHENTICATION_FAILURE => 'onAuthenticationFailure', // no need for this at that moment
            SecurityEvents::INTERACTIVE_LOGIN => 'onSecurityInteractiveLogin', // this ist what you want
        );
}

а затем onSecurityInteractiveLogin сам метод.

public function onSecurityInteractiveLogin( InteractiveLoginEvent $event )
{
    $user = $this->tokenStorage->getToken()->getUser();
    if( $user instanceof User )
    {
      $user->setLastLogin( new \DateTime() );
      $this->entityManager->flush();
    }
}

PS FosUserBundle использует interactive_login и пользовательское событие для установки last_login при просмотре сущности: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/EventListener/LastLoginListener.php

Друг, вы можете использовать это, чтобы ввести entityManager с помощью конструктора

use Doctrine\ORM\EntityManagerInterface;

public function __construct(EntityManagerInterface $userManager){
    $this->userManager = $userManager;
}

И в checkPreAuth вы называете это

public function checkPreAuth(UserInterface $user){
    if (!$user instanceof AppUser) {
        return;
    }
    if ( $user->getDeleted() || !$user->getEnabled()  ){
        throw new AuthenticationException();
    }else{
        // BELOW IS WHAT I TRY, BUT FAIL.
        $user->setLastLogin(new \DateTime());
        $this->userManager->persist($user);
        $this->userManager->flush();
    }
}
Другие вопросы по тегам