我正在使用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';
}
}
答案 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。但是,看起来如果您使用自己的存储库,则不需要定义属性(因为它是在查询中定义的)。