Symfony 4 通过用户名更改密码 - 电子邮件不能为空 [英] Symfony 4 change password by username - email can not be null

查看:36
本文介绍了Symfony 4 通过用户名更改密码 - 电子邮件不能为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介

我一直在尝试弄清楚如何创建一个受用户名值控制的重置密码表单.

错误

Path Message Invalid value Violationdata.email 此值不应为空.空值ConstraintViolation {#945 ▼-message: "此值不应为空."-messageTemplate: "此值不应为空."-参数:[▶]-复数:空-root: 表格 {#620 ▶}-propertyPath: "data.email"-无效值:空-约束:NotBlank {#477 ...}-代码:c1051bb4-d103-4f74-8988-acbcafc7fdc3"-原因:空}

预期

使用新密码更新我的用户对象.

我的代码

ForgotController.php

我知道这可能不是获取密码的正确方法,但是搜索 Symfony 4 忘记密码表单会显示与我的版本无关的 symfony2.4 帖子

 getDoctrine()->getManager();$changePassword = $request->request->get('change_password');$username = $changePassword['username'];$password = $changePassword['plainPassword']['first'];$user = $entityManager->getRepository(User::class)->findBy(['username' => $username]);$userEntity = new User();如果(!$用户){$this->addFlash('danger', '找不到用户名.$username);}$form = $this->createForm(ChangePasswordType::class, $userEntity);$form->handleRequest($request);如果 ($form->isSubmitted() && $form->isValid()) {尝试 {$pass = $encoder->encodePassword($userEntity, $password);$userEntity->setPassword($pass);$entityManager->flush();$this->addFlash('success', '密码已更改!');} 捕获(异常 $e){$this->addFlash('danger', '有些东西歪了-如果.请再试一次.');}返回 $this->redirectToRoute('login');}return $this->render('user/forgot.html.twig', array('form' => $form->createView()));}}

ChangePasswordType.php

add('username', TextType::class)->add('plainPassword', RepeatedType::class, array('类型' =>密码类型::类,'first_options' =>array('label' => '新密码'),'second_options' =>array('label' => '重复新密码')));}公共函数 configureOptions(OptionsResolver $resolver){$resolver->setDefaults(array('data_class' =>用户::类));}}

forgot.html.twig

{% 包含 'builder/header.html.twig' %}<div class="user-container" id="user-content">{% 块体 %}{% 包含 'builder/notices.html.twig' %}<div class="user-container"><i class="fas fa-user-edit fa-5x"></i>

<小时/>{{ form_start(form) }}{{ form_row(form.username, { 'attr': {'class': 'form-control'} }) }}{{ form_row(form.plainPassword.first, { 'attr': {'class': 'form-control'} }) }}{{ form_row(form.plainPassword.second, { 'attr': {'class': 'form-control'} }) }}<div class="register-btn-container"><button class="btn btn-danger" id="return-to-dash-btn" type="button">取消!</button><button class="btn btn-primary" type="submit">更新!</button>

{{ form_end(form) }}{% 结束块 %}

{% 包含 'builder/footer.html.twig' %}

我不确定为什么会提到电子邮件,除非它试图将新用户插入数据库,但它不应该根据我的控制器尝试这样做?如何添加由用户名标识的忘记密码表单?

解决方案

由于您的更改密码表单只需要两个字段,我们将使用数组而不是用户实体.需要对 ChangePasswordType 稍作调整:

//更改密码类型公共函数 configureOptions(OptionsResolver $resolver){$resolver->setDefaults(array(//'data_class' =>用户::类));}

这是一个有效的忘记操作:

 公共函数忘记了(请求 $request,UserPasswordEncoderInterface $encoder,UserRepository $userRepository){$userInfo = ['用户名' =>null, '普通密码' =>空值];$form = $this->createForm(ChangePasswordType::class, $userInfo);$form->handleRequest($request);如果 ($form->isSubmitted() && $form->isValid()) {$userInfo = $form->getData();$username = $userInfo['username'];$plainPassword = $userInfo['plainPassword'];$user = $userRepository->findOneBy(['username' => $username]);如果($user === null){$this->addFlash('danger', '无效用户名');返回 $this->redirectToRoute('忘记');}$password = $encoder->encodePassword($user, $plainPassword);$user->setPassword($password);$userRepository->flush();返回 $this->redirectToRoute('login');}return $this->render('user/forgot.html.twig', array('form' => $form->createView()));}

UserRepository 被注入,摆脱了所有的学说废话.这里有一个警告,我会回到.

我们构建 userInfo 数组并让表单处理完成它的工作.如果不需要,我们真的不想直接从请求对象中获取属性.

然后我们让我们的实际用户实体更新.请注意使用 findOneBy 而不是 findBy.我们检查以确保用户名有效.如果您真的想变得有趣,那么您可以向表单添加验证约束以自动执行此检查.

我摆脱了所有 try/catch 的东西.它只会弄乱你的代码.此时,如果抛出异常,则它确实是异常的,可以由默认异常处理程序处理.

您正确使用了密码编码器.

然后我用 $userRepository->flush() 代替 $entityManager->flush();开箱即用的存储库没有刷新方法,因此您需要添加一个:

//UserRepository公共函数flush(){$this->_em->flush();}

我个人喜欢只处理存储库而不是实体管理器.但是如果需要,您可以返回并注入管理器而不是存储库.您的来电.

正如评论中提到的,您确实希望添加一些安全措施以防止用户更改其他用户的密码.

Introduction

I have been trying to figure out how to create a reset password form that's governed by username value.

The Error

Path        Message                           Invalid value     Violation
data.email  This value should not be blank.   null 



ConstraintViolation {#945 ▼
  -message: "This value should not be blank."
  -messageTemplate: "This value should not be blank."
  -parameters: [▶]
  -plural: null
  -root: Form {#620 ▶}
  -propertyPath: "data.email"
  -invalidValue: null
  -constraint: NotBlank {#477 …}
  -code: "c1051bb4-d103-4f74-8988-acbcafc7fdc3"
  -cause: null
}

What's expected

Update my User Object with the new password.

My Code

ForgotController.php

I know this probably isn't the correct way to get the password, but searching Symfony 4 forgotten password form brings up symfony2.4 posts which aren't relevant to my version

    <?php
        namespace App\Controller\User;

        use App\Entity\User;
        use App\Form\User\ChangePasswordType;
        use App\Repository\UserRepository;
        use Symfony\Bundle\FrameworkBundle\Controller\Controller;
        use Symfony\Component\HttpFoundation\Request;
        use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

        class ForgotController extends Controller
        {
            public function forgot(Request $request, UserPasswordEncoderInterface $encoder)
            {
                $entityManager = $this->getDoctrine()->getManager();

                $changePassword = $request->request->get('change_password');

                $username = $changePassword['username'];
                $password = $changePassword['plainPassword']['first'];

                $user       = $entityManager->getRepository(User::class)->findBy(['username' => $username]);
                $userEntity = new User();

                if (!$user) {
                    $this->addFlash('danger', 'User not found for '. $username);
                }

                $form = $this->createForm(ChangePasswordType::class, $userEntity);
                $form->handleRequest($request);

                if ($form->isSubmitted() && $form->isValid()) {
                    try {
                        $pass = $encoder->encodePassword($userEntity, $password);

                        $userEntity->setPassword($pass);
                        $entityManager->flush();

                        $this->addFlash('success', 'Password Changed!');
                    } catch (Exception $e) {
                        $this->addFlash('danger', 'Something went skew-if. Please try again.');
                    }

                    return $this->redirectToRoute('login');
                }

                return $this->render('user/forgot.html.twig', array('form' => $form->createView()));
            }
        }

ChangePasswordType.php

<?php
    namespace App\Form\User;

    use App\Entity\User;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\Extension\Core\Type\PasswordType;
    use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;

    class ChangePasswordType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('username', TextType::class)
                ->add('plainPassword', RepeatedType::class, array(
                'type' => PasswordType::class,
                'first_options' => array('label' => 'New Password'),
                'second_options' => array('label' => 'Repeat New Password')
            ));
        }

        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => User::class
            ));
        }
    }

forgot.html.twig

{% include 'builder/header.html.twig' %}

<div class="user-container" id="user-content">
    {% block body %}
        {% include 'builder/notices.html.twig' %}

        <div class="user-container">
            <i class="fas fa-user-edit fa-5x"></i>
        </div>

        <hr />

        {{ form_start(form) }}
            {{ form_row(form.username, { 'attr': {'class': 'form-control'} }) }}
            {{ form_row(form.plainPassword.first, { 'attr': {'class': 'form-control'} }) }}
            {{ form_row(form.plainPassword.second, { 'attr': {'class': 'form-control'} }) }}

            <div class="register-btn-container">
                <button class="btn btn-danger" id="return-to-dash-btn" type="button">Cancel!</button>
                <button class="btn btn-primary" type="submit">Update!</button>
            </div>
        {{ form_end(form) }}
    {% endblock %}
</div>

{% include 'builder/footer.html.twig' %}

I'm not sure why email is even being mentioned unless it's trying to insert a new user into a database but it shouldn't be trying to do that based on my controller? How can I go about adding a forgot password form that's identified by username?

解决方案

Since your change password form only needs two fields we will use an array instead of a user entity. Need a slight tweak to ChangePasswordType:

    // ChangePasswordType
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            //'data_class' => User::class
        ));
    }

Here is a working forgot action:

    public function forgot(
        Request $request, 
        UserPasswordEncoderInterface $encoder, 
        UserRepository $userRepository)
    {

        $userInfo = ['username' => null, 'plainPassword' => null];

        $form = $this->createForm(ChangePasswordType::class, $userInfo);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {

            $userInfo = $form->getData();
            $username = $userInfo['username'];
            $plainPassword = $userInfo['plainPassword'];

            $user = $userRepository->findOneBy(['username' => $username]);
            if ($user === null) {
                $this->addFlash('danger', 'Invalid username');
                return $this->redirectToRoute('forgot');
            }
            $password = $encoder->encodePassword($user, $plainPassword);

            $user->setPassword($password);
            $userRepository->flush();

            return $this->redirectToRoute('login');
        }

        return $this->render('user/forgot.html.twig', array('form' => $form->createView()));
    }

UserRepository is injected which get's rid of all the doctrine nonsense. There is one caveat here that I'll get back to.

We build the userInfo array and let the form processing do it's thing. We really don't want to mess with getting attributes directly from the request object if we don't have to.

Then we get our actual user entity to update. Notice the use of findOneBy instead of findBy. We check to make sure username is valid. If you really wanted to get fancy then you could add a validation constraint to the form to do this check automatically.

I got rid of all the try/catch stuff. It just clutters up your code. By this point if an exception is thrown then it is truly exceptional and can be handled by the default exception handlers.

You got the password encoder stuff just right.

And then instead of $entityManager->flush() I used $userRepository->flush(); Out of the box there is no flush method on repositories so you need to add one:

// UserRepository
public function flush()
{
    $this->_em->flush();
}

I personally like dealing with just repositories and not the entity manager. But if want, you can just go back and inject the manager instead of the repository. Your call.

And as mentioned in the comments, you do want to add some security to prevent users from changing other users passwords.

这篇关于Symfony 4 通过用户名更改密码 - 电子邮件不能为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
PHP最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆