symfony2通过用户名或电子邮件登录

时间:2011-11-30 12:27:30

标签: email symfony authentication username

我正在使用Symfony2的标准身份验证机制,我想让用户使用他的用户名或电子邮件登录,但我不知道为什么它不起作用。我已经测试了存储库类,它按预期工作。我跟着这个how-to

这是我的用户提供程序类:

<?php

namespace My\UserBundle\Entity;

use Doctrine\ORM\EntityRepository ,
Symfony\Component\Security\Core\User\UserProviderInterface ,
Symfony\Component\Security\Core\User\UserInterface;

/**
* UserRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class UserRepository extends EntityRepository implements UserProviderInterface 
{
    function loadUserByUsername($username)
    {

        $qb = $this->createQueryBuilder('u') ;
        return 
        $qb->select('u')
        ->where(
            $qb->expr()->orx(
                $qb->expr()->like('u.username' ,':username') ,
                $qb->expr()->like('u.email' ,':username')
            )
        )
        //->andWhere($qb->expr()->eq('u.enabled' ,'true') )
        ->setParameters(array('username' =>$username ) )        
        ->getQuery()
        ->getResult() ;                  
    }

    function refreshUser(UserInterface $user)
    {
        return $this->loadUserByUsername($user->getUsername() );
    }

    function supportsClass($class)
    {
        return $class === 'My\UserBundle\Entity\User';
    }

}

4 个答案:

答案 0 :(得分:7)

我提出了一种更简单的方法,只需要编辑security.yml 文件。

您必须创建两个不同的安全提供程序,但两者都使用相同的User类。第一个用用户名作为属性,第二个用电子邮件作为属性。

然后创建一个 chain_provider ,其中包含两个提供程序并在防火墙部分使用它

security:

    providers:
        chain_provider:
            chain:
                providers: [db_username, db_email]
        db_username:
            entity:
                class: MyUserBundle:User
                property: username
        db_email:
            entity:
                class: MyUserBundle:User
                property: email

    firewalls:

        default:
            anonymous: ~            
            provider: chain_provider
            form_login:
                login_path: /login
                check_path: /login

我不知道这种方法是否是一种干净的做法,但是快速,简单且工作正常。

答案 1 :(得分:2)

好吧,伙计们,我的安全。我有这个

providers:
        main:
            entity: { class: My\UserBundle\Entity\User ,property : username}

所以我不得不取消参数property :username

答案 2 :(得分:1)

取消属性:用户名可让 UserProviderInterface 在用户登录时按预期加载用户,但不会调用 refreshUser()方法如预期。我检查了它是否被调用,但它没有。

在每次访问时重新加载用户的类是 ContextListener :: refreshUser(TokenInterface $ token)方法。在此,接口遍历UserProviders并调用首先返回非null用户的refreshUser。

我可以确定这一点,因为在原始加载中,我将所有不同的实体组合起来进行一次SQL调用而不是7.当用户重新加载时,它会调用7次。

方法 EntityUserProvider :: refreshUser()也不会调用存储库的方法,而是直接从数据库重新加载。

答案 3 :(得分:0)

您的提供程序类是正确的,并且您的问题在security.yml中是正确的,但是,您的解决方案是错误的。

根据documentation,您的security.yml文件应如下所示:

security:
# ...
providers:
    administrators:
        entity: { class: MyUserBundle:User }

请注意,该类被定义为Bundle,而不是直接类。 你现在拥有代码的方式,symfony完全忽略你的存储库类,直到你正确定义security.yml。正如@Anand所指出的,只是删除属性不会调用refreshUser。但是,看起来如果您使用自己的存储库,则不需要定义属性(因为它是在查询中定义的)。