Проверка пароля в Symfony2 - PullRequest
10 голосов
/ 01 апреля 2012

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

(Кстати, теперь я понимаю, что существуют такие вещи, как FOSUserBundle, которые позаботятся о многих из этих вещей для меня, но я уже построил свою систему аутентификации на основе официальной документации 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 ]

11 голосов
/ 01 апреля 2012

Для Symfony 2.1 существует встроенное ограничение .


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

Во-вторых, поскольку вы, вероятно, не хотите добавлять поле для текущего пароля в класс User только для того, чтобы привязать к нему ограничение, вы можете использовать то, что называется модель формы . По сути, вы создаете класс в пространстве имен 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 , поэтому я не передаю соль в качестве третьего аргумента методу $encoder->isPasswordValid(), но я думаю, что вы сможете адаптировать этот пример к вашим потребностям сами.

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

6 голосов
/ 13 октября 2012

В 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

0 голосов
/ 03 апреля 2012

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

0 голосов
/ 01 апреля 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...