Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 password reset without overriding FOSUser

Tags:

php

symfony

I am trying to build a form that resets user password. I am using FOSUserBundle to manage users, but I don't want to override FOSUser resetting controller due to some architecture reasons

So I decided to build my own type and controller to reset password

PasswordResettingType.php

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('plainPassword', RepeatedType::class, array(
        'type' => PasswordType::class,
        'attr' => ['class' => 'form-group has-feedback'],
        'first_options' => array('label' => false,
            'attr' => ['placeholder' => 'New Password']
            ),
        'second_options' => array('label' => false,
            'attr' => ['placeholder' => 'Repeat Password']),
        'invalid_message' => 'Passwords don't match',
    ));
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'CoreBundle\Entity\User',
        'csrf_token_id' => 'resetting'
    ));
}

Resetting controller

/**
 * @Route("/reset/{token}", name="api_resetting_reset")
 */
public function resetAction(Request $request, $token)
{
    $userManager = $this->get('fos_user.user_manager');

    $user = $userManager->findUserByConfirmationToken($token);

    if (null === $user) {
        return $this->render('APIBundle:Resetting:error.html.twig');
    }

    $form = $this->createForm(PasswordResettingType::class, $user);

    $form->handleRequest($request);

    if ($form->isValid()) {
        $user->setConfirmationToken(null);
        $user->setPasswordRequestedAt(null);
        $user->setPlainPassword($form["plainPassword"]->getData());
        $userManager->updateUser($user);

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

    return $this->render('APIBundle:Resetting:reset.html.twig', array(
        'token' => $token,
        'form' => $form->createView()
    ));
}

reset.html.twig

{{ form_start(form) }}

        {% for passwordField in form.plainPassword %}
            <div class="form-group has-feedback">
                {{ form_widget(passwordField, { 'attr': {'class': 'form-control'} }) }}
                <span class="show">show</span>
                {{ form_errors(passwordField) }}
            </div>
        {% endfor %}

    <input type="submit" class="btn" value="Submit" />
{{ form_end(form) }}

But when I submit form, new password is not set, ConfirmationToken and PasswordRequestedAt are not set to null.

like image 419
blahblah Avatar asked Oct 14 '16 15:10

blahblah


1 Answers

I think you are doing it the wrong way. If you take a look to FOS User and read with detail the documentation, you will see that they are doing this using EventListeners.

That means you can hook on them and do your stuff. Or if you don't want to do it you can override it and make your own. Doing this half way like you are doing is not going to work properly. For example you are not checking the onResettingResetInitialize event that checks if the password request expired.

About last answer I think you don't really need to do this:

$encoder = $this->container->get('security.password_encoder');
$user->setPassword($encoder->encodePassword($user, $user->getPlainPassword()));

Since that is the job of the UserManager->UpdateUser()

By the way: Can't you debug from there and put a dump($user);exit(); and check what's the output and if it's being called properly.

Also Boulzy comment is right: /reset/{token} is the same route of FOS. If you debug the UpdateUser using echo debug_backtrace(); you can also see from where is being called the UpdateUser.

like image 85
Martin Fasani Avatar answered Oct 27 '22 17:10

Martin Fasani