【问题标题】:UserChecker - Use entity managerUserChecker - 使用实体管理器
【发布时间】:2019-01-27 11:09:21
【问题描述】:

我的网站正在运行 Symfony 3.4,我创建了自己的用户会员系统。 我的用户实体包含一个日期时间字段“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-&gt;get('doctrine')-&gt;getManager();,我会得到:

致命错误:调用未定义的方法 CoreBundle\Security\UserChecker::get()

【问题讨论】:

  • 您的具体问题是什么?什么失败了?您收到任何错误消息吗?
  • 它会给你任何错误。 .我想它会抛出关于没有可用的 get 函数的错误。 .对吗?
  • 一个关于约定的非常小的建议:您不应该将 getDeleted 或 getEnabled 用于布尔方法,而应使用 isDeleted 和 isEnabled。
  • 我编辑了我的第一个主题,但出现了错误。过失。
  • 看起来您找到了解决方案。一个很好的。但是,如果您像下面的侦听器一样注入实体管理器,则上述代码将起作用。尽量避免在你的控制器中使用 getDoctrine。我可能会补充一点,最好使用直接 sql 更新您的数据库。如果您的代码的其他部分已经在使用实体管理器,那么刷新它可能会导致意外结果。

标签: symfony symfony-3.4 symfony-security


【解决方案1】:

不知道为什么@doncallisto 删除了他的帖子。这是(恕我直言)正确的事情。

看看http://symfony.com/doc/current/components/security/authentication.html#authentication-success-and-failure-events

所以你有几个选择。

  • SecurityEvents::INTERACTIVE_LOGIN - 每次用户触发 填写登录表单并提交凭据。会工作,但你 如果您有 remember_me cookie 或类似信息,不会获得 last_login 更新

  • 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();
    }
}

附: FosUserBundle 使用 interactive_login 和自定义事件在实体上设置 last_login 看:https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/EventListener/LastLoginListener.php#L63

【讨论】:

  • 创建 EventSuscriber 非常完美!谢谢。我没有考虑过。最好的办法是将所有身份验证过程检查集中在同一个文件中:isEnabled?被删除了吗?更新上次登录。
【解决方案2】:

朋友,您可以使用它通过构造函数注入 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();
    }
}

【讨论】:

    猜你喜欢
    • 2012-06-28
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多