symfony2 вход по имени пользователя или электронной почте - PullRequest
5 голосов
/ 30 ноября 2011

Я использую стандартный механизм аутентификации Symfony2 и хочу, чтобы пользователь использовал свое имя пользователя или адрес электронной почты для входа, но я не могу понять, почему он не работает. Я протестировал класс репозитория, и он работает как ожидалось. Я следовал этому инструкции .

Вот мой класс провайдера:

<?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 ]

7 голосов
/ 03 марта 2016

Я предлагаю более простой подход, который требует только для редактирования файла security.yml .

Необходимо создать двух разных поставщиков безопасности, но оба с одним и тем же классом пользователя. Первый имеет имя пользователя в качестве свойства, а второй имеет email в качестве свойства.

Затем вы создаете 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

Я не знаю, является ли этот подход чистой практикой, но он быстр, прост и работает нормально.

2 голосов
/ 01 декабря 2011

ну, ребята, дело в моей безопасности. У меня было это

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

, поэтому мне пришлось снять этот параметр property :username

1 голос
/ 15 марта 2012

Снятие свойства : username позволяет UserProviderInterface загружать пользователя, как ожидается, когда он входит в систему, но не вызывает метод refreshUser () какожидается.Я вставил проверки, чтобы увидеть, вызывается ли он, но это не так.

Класс, который перезагружает пользователя при каждом доступе, это ContextListener :: refreshUser (TokenInterface $ token) метод.В этом интерфейс перебирает UserProviders и вызывает refreshUser, который сначала возвращает ненулевого пользователя.

Я мог бы убедиться в этом, потому что в исходной загрузке я объединяю все разные объекты, чтобы сделать один вызов SQLвместо 7. И когда пользователь перезагружается, он вызывает 7 раз.

Также метод EntityUserProvider :: refreshUser () не вызывает метод репозитория и вместо этого перезагружается из базы данных напрямую..

0 голосов
/ 06 марта 2013

Ваш класс провайдера правильный, и вы правы, что проблема в security.yml, однако ваше решение неверно.

Согласно документации , ваш security.ymlФайл должен выглядеть следующим образом:

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

Обратите внимание, что класс определен как Bundle, а не как прямой класс.Как у вас есть ваш код прямо сейчас, Symfony полностью игнорирует ваш класс хранилища, пока вы не определите ваш security.yml правильно.И, как указал @Anand, простое удаление свойства не вызывает refreshUser.Однако, похоже, что если вы используете свой собственный репозиторий, вам не нужно определять это свойство (так как оно определяется в вашем запросе).

...