在Symfony2中验证密码

Jas*_*ett 10 symfony

我正在尝试在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);
  }
}
Run Code Online (Sandbox Code Playgroud)

正如您在我的评论中所看到的,至少有几个原因导致上述代码不起作用.我只想发布有关这些特定问题的具体问题,但也许我正在咆哮错误的树.这就是我问整体问题的原因.

那么,我该如何验证用户的密码?

Eln*_*mov 11

自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';
    }
}
Run Code Online (Sandbox Code Playgroud)

它的验证器:

<?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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用我的Blofwish密码编码器包,所以我不会将salt作为该$encoder->isPasswordValid()方法的第三个参数传递,但我认为您将能够自己调整此示例以满足您的需求.

此外,我正在使用JMSDiExtraBundle简化开发,但您当然可以使用经典的服务容器配置方式.


Ben*_*Ben 6

在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()))
Run Code Online (Sandbox Code Playgroud)

显然现在有一个错误的验证器,所以可能或现在可能工作 https://github.com/symfony/symfony/issues/5460