【问题标题】:Validating a password in Symfony2在 Symfony2 中验证密码
【发布时间】:2012-04-01 15:50:07
【问题描述】:

我正在尝试在 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);
  }
}

正如您在我的 cmets 中看到的,上述代码不起作用至少有几个原因。我只会发布有关这些特定问题的具体问题,但也许我完全是在找错树。这就是我提出整体问题的原因。

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

【问题讨论】:

    标签: symfony


    【解决方案1】:

    我最终斩断了快死结。我绕过了 Symfony 的所有表单内容,并在控制器中完成了所有逻辑。

    【讨论】:

    • 嘿,您应该使用新的 UserPassword 验证约束再试一次。
    • 被低估的答案
    【解决方案2】:

    自 Symfony 2.1 以来就有一个built-in constraint


    首先,您应该创建一个custom validation constraint。您可以将验证器注册为服务并在其中注入您需要的任何内容。

    其次,由于您可能不想将当前密码的字段添加到 User 类,只是为了将约束固定在它上面,您可以使用所谓的form model。本质上,您在 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,所以我没有将盐作为第三个参数传递给$encoder-&gt;isPasswordValid() 方法,但我认为您可以根据自己的需要调整此示例。

    另外,我使用JMSDiExtraBundle来简化开发,不过你当然可以使用经典的服务容器配置方式。

    【讨论】:

    • 好的,谢谢。但是实际的密码验证部分呢?这就是我的问题要问的。我已经知道如何创建自定义验证器以及如何创建表单字段。
    • 我在连接它时遇到了一些麻烦。针对我的子问题开始了一个单独的问题:stackoverflow.com/questions/9967166/…
    • @Validator 注释是否应该使User 类知道使用此验证器?如果没有,那部分如何进行?谢谢。
    • 它允许您在任何类上使用约束作为注释。此验证器中没有任何内容将其仅限于 User 类。
    • 好的,那么我如何告诉User 类使用CustomPasswordValidator
    【解决方案3】:

    在 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

    【讨论】:

    • 一个小注,有错别字,应该是Symfony\Component\Security\Core\Validator\Constraints\UserPassword(Contraints中没有s
    【解决方案4】:

    FOSUserBundle 使用与基类 Model 分开的 ModelManager 类。你可以查看他们的implementation

    【讨论】:

      猜你喜欢
      • 2015-08-21
      • 1970-01-01
      • 2011-08-29
      • 2019-05-30
      • 1970-01-01
      • 1970-01-01
      • 2011-01-24
      • 1970-01-01
      相关资源
      最近更新 更多