Как использовать фабрику кодировщиков в Symfony 2 внутри установщика моделей?

Этот вопрос о Symfony 2.1

Как я могу кодировать пароль пользователя с помощью:

$factory = $this->get('security.encoder_factory');
$user = new Acme\UserBundle\Entity\User();

$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword('ryanpass', $user->getSalt());
$user->setPassword($password);

И базовый конфиг:

# app/config/security.yml
security:
    # ...

    encoders:
        Acme\UserBundle\Entity\User: sha512

Внутри сеттера модели:

class User implements UserInterface, \Serializable
{
    public function setPassword($password)
    {
       $this->password = $password;
    }
}

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

2 ответа

Решение

Сущность содержит данные, а не обрабатывает их. Если вы хотите изменить данные сущности, вы можете создать прослушиватель событий и делать что-то перед сохранением. Проверьте, как зарегистрировать слушателей событий и подписчиков из официальной документации.

Вы также можете взглянуть на FosUserBundle и его управление пользователями.

FosUserBundle UserManager

Итак, основная идея состоит в том, чтобы передать простой пароль из формы в пользовательский объект и зашифровать его перед сохранением с помощью прослушивателя событий.

Хотя я согласен с @Vadim в том, что вы не должны передавать бизнес-логику в свою модель, я бы с осторожностью отложил хеширование открытого текста до prePersist событие, например, если вы не позвоните persist а также flush сразу после setPassword, getPassword Тем временем call будет возвращать текстовую строку, если вы не сохранили ее в отдельном поле, что может иметь серьезные последствия. В идеале открытый текстовый пароль должен существовать как можно более короткое время в течение жизненного цикла приложения.

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

class UserManager
{
    // ...
    public function __construct(EncoderFactoryInterface $encoderFactory)
    {
        // $encoderFactory is injected by the DIC as requested by your service configuration
        // ...
    }

    public function setUserPassword(UserInterface $user, $plaintextPassword)
    {
        $hash = $this->encoderFactory->getEncoder($user)->encodePassword($plaintextPassword, null);
        $user->setPassword($hash);
    }
    // ...
}

В вашем контроллере для отправки регистрационной формы, например:

public function userRegistrationAction()
{
    // ... 
    if ($form->isValid()) {
        $user = new User();
        // ...
        $this->get('my.bundle.user_manager')->setUserPassword($user, $form->get('password')->getData());
        // ...
    }
}
Другие вопросы по тегам