Проверка пароля в Symfony2

Я пытаюсь собрать функцию смены пароля в Symfony2. У меня есть поле" текущий пароль", поле" новый пароль "и поле" подтвердить новый пароль", и часть, на которой я сейчас фокусируюсь, проверяет поле" текущий пароль".

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

то, что я воображаю / надеюсь, что смогу сделать, это создать обратный вызов проверки, который говорит что-то вроде этого:

// Entity/User.php

public function currentPasswordIsValid(ExecutionContext $context)
{
  $currentPassword = $whatever; // whatever the user submitted as their current password
  $factory = $this->get('security.encoder_factory'); // Getting the factory this way doesn't work in this context.
  $encoder = $factory->getEncoder($this);
  $encryptedCurrentPassword = $encoder->encodePassword($this->getPassword(), $this->getSalt());

  if ($encyptedCurrentPassword != $this->getPassword() {
    $context->addViolation('Current password is not valid', array(), null);
  }
}

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

Итак, как я могу проверить пароль пользователя?

4 ответов


здесь встроенные ограничения для этого с Symfony 2.1.


во-первых, вы должны создать пользовательское ограничение проверки. Вы можете зарегистрировать валидатор как услугу и ввести в него все, что вам нужно.

во-вторых, поскольку вы, вероятно, не хотите добавлять поле для текущего пароля в класс пользователя, чтобы просто придерживаться ограничения, вы можете использовать то, что называется модель форма. По сути, вы создаете класс Form\Model пространство имен, содержащее текущее поле пароля и ссылку на объект пользователя. Вы можете вставить свое пользовательское ограничение в это поле пароля. Затем вы создаете тип формы изменения пароля для этой модели формы.

вот пример ограничения из одного из моих проектов:

<?php
namespace Vendor\Bundle\AppBundle\Validator\Constraints\User;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class CurrentPassword extends Constraint
{
    public $message = "Your current password is not valid";

    /**
     * @return string
     */
    public function validatedBy()
    {
        return 'user.validator.current_password';
    }
}

и его валидатор:

<?php
namespace Vendor\Bundle\AppBundle\Validator\Constraints\User;

use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
use JMS\DiExtraBundle\Annotation\Validator;
use JMS\DiExtraBundle\Annotation\InjectParams;
use JMS\DiExtraBundle\Annotation\Inject;

/**
 * @Validator("user.validator.current_password")
 */
class CurrentPasswordValidator extends ConstraintValidator
{
    /**
     * @var EncoderFactoryInterface
     */
    private $encoderFactory;

    /**
     * @var SecurityContextInterface
     */
    private $securityContext;

    /**
     * @InjectParams({
     *     "encoderFactory"  = @Inject("security.encoder_factory"),
     *     "securityContext" = @Inject("security.context")
     * })
     *
     * @param EncoderFactoryInterface  $encoderFactory
     * @param SecurityContextInterface $securityContext
     */
    public function __construct(EncoderFactoryInterface  $encoderFactory,
                                SecurityContextInterface $securityContext)
    {
        $this->encoderFactory  = $encoderFactory;
        $this->securityContext = $securityContext;
    }

    /**
     * @param string     $currentPassword
     * @param Constraint $constraint
     * @return boolean
     */
    public function isValid($currentPassword, Constraint $constraint)
    {
        $currentUser = $this->securityContext->getToken()->getUser();
        $encoder = $this->encoderFactory->getEncoder($currentUser);
        $isValid = $encoder->isPasswordValid(
            $currentUser->getPassword(), $currentPassword, null
        );

        if (!$isValid) {
            $this->setMessage($constraint->message);
            return false;
        }

        return true;
    }
}

я использую blofwish password encoder bundle, поэтому я не передаю соль в качестве третьего аргумента the $encoder->isPasswordValid() метод, но я думаю, что вы сможете адаптировать этот пример к своим потребностям самостоятельно.

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


в Symfony 2.1 вы можете использовать встроенный валидатор: http://symfony.com/doc/master/reference/constraints/UserPassword.html

Так, например, в конструктор форм:

// declare
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;

// mapped=>false (new in 2.1) is to let the builder know this is not an entity field
->add('currentpassword', 'password', array('label'=>'Current password', 'mapped' => false, 'constraints' => new UserPassword()))

по-видимому, сейчас есть ошибка с этим валидатором, поэтому может или может работать https://github.com/symfony/symfony/issues/5460


FOSUserBundle использует ModelManager класс, который отделен от базы модель. Вы можете проверить их реализация.


Я закончил тем, что разрубил гордиев узел. Я обошел все формы Symfony и сделал всю логику в контроллере.