为什么我的用户登录在升级到 Symfony3 后不再有效

Why is my User Login no longer working after upgrading to Symfony3

我遇到了 Symfony 3 的一个奇怪问题。 在 Symfony 2 下,一切都开箱即用(登录)。 但在 Symfony 3 下,它根本无法验证。 Doctrine 层未加载我的用户对象或存储库。

怎么回事?

好的,简短的更新。 我能够解决这个问题,并想分享发生的事情。 在调试完整的登录过程后,我偶然发现了无法登录的主要原因。

<?php
    // src/AppBundle/Entity/UserRepository.php
    namespace AppBundle\Entity;

    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Security\Core\User\UserProviderInterface;
    use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
    use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
    use Doctrine\ORM\EntityRepository;

    class UserRepository extends EntityRepository implements UserProviderInterface
    {
        public function loadUserByUsername($username)
        {
            $user = $this->createQueryBuilder('u')
                ->where('u.username = :username OR u.email = :email')
                ->setParameter('username', $username)
                ->setParameter('email', $username)
                ->getQuery()
                ->getOneOrNullResult();

            if (null === $user) {
                $message = sprintf(
                    'Unable to find an active admin AppBundle:User object identified by "%s".',
                    $username
                );
                throw new UsernameNotFoundException($message);
            }

            return $user;
        }

        public function refreshUser(UserInterface $user)
        {
            $class = get_class($user);
            if (!$this->supportsClass($class)) {
                throw new UnsupportedUserException(
                    sprintf(
                        'Instances of "%s" are not supported.',
                        $class
                    )
                );
            }

            return $this->find($user->getId());
        }

        public function supportsClass($class)
        {
            return $this->getEntityName() === $class
                || is_subclass_of($class, $this->getEntityName());
        }
    }

好的, 这个 Repository Query Class 实际上是它不起作用的原因。 在调试和测试之后,我在 Class:

中找到了这个代码块

Symfony\Bridge\Doctrine\Security\User

/**
 * {@inheritdoc}
 */
public function loadUserByUsername($username)
{
    if (null !== $this->property) {
        $user = $this->repository->findOneBy(array($this->property => $username));
    } else {
        if (!$this->repository instanceof UserLoaderInterface) {
            throw new \InvalidArgumentException(sprintf('The Doctrine repository "%s" must implement Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface.', get_class($this->repository)));
        }

        $user = $this->repository->loadUserByUsername($username);
    }

    if (null === $user) {
        throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
    }

    return $user;
}

它声明 Repository Class 必须是 UserLoaderInterface 的一个实例。 但是

的文档

http://symfony.com/doc/current/cookbook/security/entity_provider.html

声明它是 UserProviderInterface 的一个实例。

所以登录失败,因为它没有实现正确的接口。 文档(Cookbook)中有一个旧信息,或者 Symfony 团队只是忘记了它。 ^^(可能发生)

希望对大家有所帮助^^

UserProviderInterface 在 2.8 中更改为 UserLoaderInterface (see doc)

  • class UserRepository 扩展了 EntityRepository 实现 UserProviderInterface
  • class UserRepository 扩展了 EntityRepository 实现 UserLoaderInterface

这将解决问题,您也可以删除这些功能:

  • public 函数 refreshUser(UserInterface $user)
  • public 函数支持类($class)

对我来说,问题是 EquatableInterface 的 isEqualTo 方法(在我的用户实体上)在应该返回 true 时返回了 false。