Partage
  • Partager sur Facebook
  • Partager sur Twitter

Symfony 4.2 problème lors du reset du mot de passe

Sujet résolu
    12 décembre 2018 à 17:47:54

    Salut tout le monde !

    Ça fait deux jours que je suis dessus et j'y arrive pas. J'ai suivi plus ou moins ce tuto : https://roadtodev.com/fr/blog/symfony-4-reset-password adapter à mon projet.

    Donc j'ai un form qui permet de mettre son ancien mot de passe et deux fois le nouveau que l'on veut mettre :

    <?php
    
    namespace App\Form;
    
    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\SubmitType;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    
    class IdentifiantType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('oldPassword', PasswordType::class, array(
            'mapped' => false,
            'label' => 'Mot de passe actuel'
        ))
            ->add('password', RepeatedType::class, array(
                'type' => PasswordType::class,
                'invalid_message' => 'Les deux mots de passe doivent être identiques',
                'options' => array(
                    'attr' => array(
                        'class' => 'password-field'
                    )
                ),
                'required' => true,
                'first_options'  => array('label' => 'Nouveau mot de passe'),
                'second_options' => array('label' => 'Répeter votre mot de passe'),
            ))
        ;
    
            return $builder;
        }
    
        /**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => User::class,
                "allow_extra_fields" => true
            ));
        }
    }

    Ensuite, j'ai mon controller qui gère uniquement cette parti du projet :

    <?php
    
    namespace App\Controller;
    
    
    use App\Entity\User;
    use App\Form\IdentifiantType;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\Form\Extension\Core\Type\SubmitType;
    use Symfony\Component\Form\FormError;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
    use Symfony\Component\HttpFoundation\Session\Session;
    use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
    use Symfony\Component\Routing\Annotation\Route;
    use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
    
    class IdentifiantController extends AbstractController
    {
        /**
         * @Route("/identifiant", name="identifiant")
         */
        public function updateIdentifiant(Request $request, UserPasswordEncoderInterface $passwordEncoder)
        {
            $em = $this->getDoctrine()->getManager();
            $user = $this->getUser();
    
            $form = $this->createForm(IdentifiantType::class, $user)
                ->add('modify', SubmitType::class, array('label' => 'Mettre à jour'));
    
            $form->handleRequest($request);
            if ($form->isSubmitted() && $form->isValid()) {
    
                $oldPassword = $request->request->get('identifiant')['oldPassword'];
    
                // Si l'ancien mot de passe est bon
                if ($passwordEncoder->isPasswordValid($user, $oldPassword)) {
                    $newEncodedPassword = $passwordEncoder->encodePassword($user, $user->getPassword());
                    $user->setPassword($newEncodedPassword);
    
                    $em->persist($user);
                    $em->flush();
    
                    $this->addFlash('notice', 'Votre mot de passe à bien été changé !');
    
                    return $this->redirectToRoute('accueil');
    } else { $form->addError(new FormError('Ancien mot de passe incorrect')); } } return $this->render('identifiant/identifiant.html.twig', array( 'form' => $form->createView(), )); } }

    Tout a l'air correct, quand je charge ma page aucune erreur mais des que j'envoie mon formulaire ça me renvoie une erreur qui me dit que mon mot de passe n'est pas bon alors que je suis sûr et certain d'avoir mis le bon mot de passe. En fait, il ne passe pas le isPasswordValid et sors du if à peine y avoir été entré :(

    Si jamais, mon entité user ;

    <?php
    
    namespace App\Entity;
    
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\Common\Collections\Collection;
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Security\Core\User\UserInterface;
    
    /**
     * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
     */
    class User implements UserInterface
    {
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue()
         * @ORM\Column(type="integer")
         */
        private $id;
    
        /**
         * @ORM\Column(type="string", length=180, unique=true)
         */
        private $email;
    
        /**
         * @ORM\Column(type="json")
         */
        private $roles = [];
    
        /**
         * @var string The hashed password
         * @ORM\Column(type="string")
         */
        private $password;
    
        /**
         * @ORM\Column(type="string", length=30)
         */
        private $nom;
    
        /**
         * @ORM\Column(type="string", length=30)
         */
        private $prenom;
    
        /**
         * @ORM\Column(type="string", length=150)
         */
        private $login;
    
        /**
         * @ORM\Column(type="string", length=30, nullable=true)
         */
        private $civilite;
    
        /**
         * @ORM\Column(type="string", length=60, nullable=true)
         */
        private $adresse;
    
        /**
         * @ORM\Column(type="string", length=5, nullable=true)
         */
        private $cp;
    
        /**
         * @ORM\Column(type="string", length=45, nullable=true)
         */
        private $ville;
    
        /**
         * @ORM\Column(type="string", length=10, nullable=true)
         */
        private $telephone;
    
        /**
         * @ORM\Column(type="string", length=10, nullable=true)
         */
        private $portable;
    
        /**
         * @ORM\Column(type="string", unique=true)
         */
        private $apiToken;
    
        /**
         * @ORM\ManyToOne(targetEntity="App\Entity\Reponse", inversedBy="user")
         */
        private $reponse;
    
        /**
         * @ORM\ManyToMany(targetEntity="App\Entity\Magasin", inversedBy="user")
         */
        private $magasin;
    
        public function __construct()
        {
            $this->magasin = new ArrayCollection();
    
        }
    
        public function getId(): ?int
        {
            return $this->id;
        }
    
        public function getEmail(): ?string
        {
            return $this->email;
        }
    
        public function setEmail(string $email): self
        {
            $this->email = $email;
    
            return $this;
        }
    
        /**
         * A visual identifier that represents this user.
         *
         * @see UserInterface
         */
        public function getUsername(): string
        {
            return (string)$this->email;
        }
    
        /**
         * @see UserInterface
         */
        public function getRoles(): array
        {
            $roles = $this->roles;
            // guarantee every user at least has ROLE_USER
            $roles[] = 'ROLE_USER';
    
            return array_unique($roles);
        }
    
        public function setRoles(array $roles): self
        {
            $this->roles = $roles;
    
            return $this;
        }
    
        /**
         * @see UserInterface
         */
        public function getPassword(): string
        {
            return (string)$this->password;
        }
    
        public function setPassword(string $password): self
        {
            $this->password = $password;
    
            return $this;
        }
    
        /**
         * @see UserInterface
         */
        public function getSalt()
        {
            // not needed when using the "bcrypt" algorithm in security.yaml
        }
    
        /**
         * @see UserInterface
         */
        public function eraseCredentials()
        {
            // If you store any temporary, sensitive data on the user, clear it here
            // $this->plainPassword = null;
        }
    
        public function getNom(): ?string
        {
            return $this->nom;
        }
    
        public function setNom(string $nom): self
        {
            $this->nom = $nom;
    
            return $this;
        }
    
        public function getPrenom(): ?string
        {
            return $this->prenom;
        }
    
        public function setPrenom(string $prenom): self
        {
            $this->prenom = $prenom;
    
            return $this;
        }
    
        public function getLogin(): ?string
        {
            return $this->login;
        }
    
        public function setLogin(string $login): self
        {
            $this->login = $login;
    
            return $this;
        }
    
        public function getCivilite(): ?string
        {
            return $this->civilite;
        }
    
        public function setCivilite(?string $civilite): self
        {
            $this->civilite = $civilite;
    
            return $this;
        }
    
        public function getAdresse(): ?string
        {
            return $this->adresse;
        }
    
        public function setAdresse(?string $adresse): self
        {
            $this->adresse = $adresse;
    
            return $this;
        }
    
        public function getCp(): ?string
        {
            return $this->cp;
        }
    
        public function setCp(?string $cp): self
        {
            $this->cp = $cp;
    
            return $this;
        }
    
        public function getVille(): ?string
        {
            return $this->ville;
        }
    
        public function setVille(?string $ville): self
        {
            $this->ville = $ville;
    
            return $this;
        }
    
        public function getTelephone(): ?string
        {
            return $this->telephone;
        }
    
        public function setTelephone(?string $telephone): self
        {
            $this->telephone = $telephone;
    
            return $this;
        }
    
        public function getPortable(): ?string
        {
            return $this->portable;
        }
    
        public function setPortable(?string $portable): self
        {
            $this->portable = $portable;
    
            return $this;
        }
    
        /**
         * @return mixed
         */
        public function getApiToken()
        {
            return $this->apiToken;
        }
    
        /**
         * @param mixed $apiToken
         */
        public function setApiToken($apiToken): void
        {
            $this->apiToken = $apiToken;
        }
    
        public function getReponse(): ?Reponse
        {
            return $this->reponse;
        }
    
        public function setReponse(?Reponse $reponse): self
        {
            $this->reponse = $reponse;
    
            return $this;
        }
    
        /**
         * @return Collection|Magasin[]
         */
        public function getMagasin(): Collection
        {
            return $this->magasin;
        }
    
        public function addMagasin(Magasin $magasin): self
        {
            if (!$this->magasin->contains($magasin)) {
                $this->magasin[] = $magasin;
                $magasin->addUser($this);
            }
    
            return $this;
        }
    
        public function removeMagasin(Magasin $magasin): self
        {
            if ($this->magasin->contains($magasin)) {
                $this->magasin->removeElement($magasin);
                // set the owning side to null (unless already changed)
                if ($magasin->getUser() === $this) {
                    $magasin->addUser(null);
                }
            }
    
            return $this;
        }
    }
    



    Si quelqu'un pouvait m'aider se serait génial !

    Excusez moi s'il y a des fautes d'orthographes ou s'il manquent du code pour que vous puissiez m'aider, un p'tit commentaire et j'vous corrige ce qu'il y a à corriger !

    Merci !


    -
    Edité par VincentBoulard2 12 décembre 2018 à 17:52:09

    • Partager sur Facebook
    • Partager sur Twitter
      13 décembre 2018 à 5:33:51

      Bonjour,

      1. pour la question posée, qu'est-ce que cela donne si tu mets comme 3ième argument à isPasswordValid, $user->getSalt() ?

      2. Je pense que ton formulaire vérifie automatiquement si ton mot de passe est le bon, sans que tu aies besoin de faire cette vérification avec is PasswordValid($user,$plainPassword,$user->getSalt()).

      Tu peux faire un essai en enlevant cette condition et en mettant un mauvais mot de passe et normalement le formulaire devrait t'afficher une erreur.

      3. Au passage, "Votre mot de passe à bien été changé !" =>

      "Votre mot de passe a bien été changé !"

      A toi

      -
      Edité par CarréDas1 13 décembre 2018 à 5:36:26

      • Partager sur Facebook
      • Partager sur Twitter
        13 décembre 2018 à 9:32:47

        Merci pour ta réponse ! 

        Après quelques essais, je peux affirmer que tes solutions ne fonctionne pas :(

        Pour la première solution, toujours le mêmes problème de l'ancien mot de passe mais en même temps je ne crois pas avec mis un salt à mon user

        La deuxième solution fonctionne mais le formulaire ne fait pas de vérification automatique, que je mette le bon ou un mauvais mot de passe, il me le change. Pourtant dans le code de mon login j'ai pas de isPasswordValid est ça fonctionne bien :

        /**
             * @Route("/login", name="login")
             */
            public function login(AuthenticationUtils $authenticationUtils): Response
            {
                // get the login error if there is one
                $error = $authenticationUtils->getLastAuthenticationError();
                // last username entered by the user
                $lastUsername = $authenticationUtils->getLastUsername();
        
                return $this->render('security/login.html.twig', [
                    'last_username' => $lastUsername,
                    'error' => $error
                ]);
            }

        Et enfin, merci pour la correction orthographique, un mauvais copié collé haha

        EDIT : Après vérification, mon $user->getSalt() est égal à NULL mais en même temps, j'utilise argon2i pour crypter mes mots depasse donc théoriquement, pas besoin de salt

        -
        Edité par VincentBoulard2 13 décembre 2018 à 9:45:40

        • Partager sur Facebook
        • Partager sur Twitter
          14 décembre 2018 à 4:41:58

          Bonjour,

          1. Voici les solutions que j'ai adoptées pour mes sites en matière de modification de profil et de mot de passe.

          2. Tout d'abord, j'ai dissocié trois cas de figure, le changement du mot de passe par son user, la modification du profil par son user (et donc avec obligatoirement la vérification du mot de passe mais sans modification de ce dernier), la modification du profil d'un user par l'administrateur sans vérification du mot de passe de l'user inconnu de l'administrateur mais réservé uniquement à l'administrateur.

          3. Pour ce dernier cas c'est une modification classique de l'entité user y compris pour changer le mot de passe avec quand même la petite subtilité suivante dans le setPassword:

          $user->setPassword($passwordEncoder->encodePassword($user, $newplainpassword));

          Rappelons que l'administrateur peut être amené à changer le mot de passe d'un user quand ce dernier a perdu ou oublié son mot de passe. Il peut également être amené à modifier les paramètres de l'utilisateur notammnent pour enrichier son profil (exemple nombre de connections, dernière date de connexion, rôle différent, note à un examen,....)

          4. Revenons sur le changement de mot de passe. Voici la solution que je propose, elle est assez simple et repose sur 1 entité créée spécifiquement sans correspondance en bdd et un formulaire correspondant. Voici donc respectivement, l'entité, le formulaire, le controler tout cela en SF4.2.

          Entité changepassword

          <?php
          //src/Entity/ChangePassword.php
          namespace App\Entity;
          
          use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
          
          class Changepassword
          {
              /**
               * @SecurityAssert\UserPassword(
               *     message = "Vous avez indiqué un mauvais mot de passe"
               * )
               */
              private $password;
              private $newPassword;
              private $plainPassword;
          public function getPlainPassword()
              {
                  return $this->plainPassword;
              }
           
              public function setPlainPassword($password)
              {
                  $this->plainPassword = $password;
              }
              public function getNewPassword()
              {
                  return $this->password;
              }
           
              public function setNewPassword($password)
              {
                  $this->password = $password;
              }
              public function getPassword()
              {
                  return $this->password;
              }
           
              public function setPassword($password)
              {
                  $this->password = $password;
              }
          }

          Formulaire ChangepasswordType

          <?php
          // src/Form/User/ChangepasswordType.php
          namespace App\Form\User;
          
          use App\Entity\Changepassword;
          use Symfony\Component\Form\AbstractType;
          use Symfony\Component\Form\FormBuilderInterface;
          use Symfony\Component\OptionsResolver\OptionsResolver;
          use Symfony\Component\Form\Extension\Core\Type\TextType;
          use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
          use Symfony\Component\Form\Extension\Core\Type\PasswordType;
          
          class ChangepasswordType extends AbstractType
          {
              public function buildForm(FormBuilderInterface $builder, array $options)
              {
                  $builder
                  ->add('password', PasswordType::class, array(
                      'mapped'=>true,
                  ))
                      ->add('plainPassword', RepeatedType::class, array(
                          'type' => PasswordType::class,
                          'first_options'  => array('label' => 'newPassword'),
                          'second_options' => array('label' => 'Repeat Password'),
                      ))
                  ;
              }
          
              public function configureOptions(OptionsResolver $resolver)
              {
                  $resolver->setDefaults(array(
                      'data_class' => Changepassword::class,
                  ));
              }
          }

          Et le controller associé:

          /**
              * @Route("/security/changepassword", name="security_changepassword")
              */
              public function ChangepasswordAction(Request $request, UserPasswordEncoderInterface $passwordEncoder,TranslatorInterface $translator,EventDispatcherInterface $dispatcher)
              {
                  // 1) edit users
                  $titre = "Change password";
                  $em = $this->getDoctrine()->getManager();
                  $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
                  $user=$this->getUser();
                  $ur=$em->getRepository('App:User');
                  $oldPassword = $user->getPassword();  
                  dump($passwordEncoder->isPasswordValid($user,'site',$user->getSalt()));
                  $change = new Changepassword();
                  $form = $this->createForm(ChangepasswordType::class, $change);
                  // 2) handle the submit (will only happen on POST)
                  $form->handleRequest($request);
                  if ($form->isSubmitted() && $form->isValid()) {
                      $password = $passwordEncoder->encodePassword($user, $change->getPlainPassword());
                      $user->setPassword($password);
                      $request->getSession()->getFlashBag()->add('succès', "New password registered");
                      // On crée l'évènement avec ses arguments
                      $parametres=$em->getRepository('App:Parametres')->findOneByActif(true);
                      $notifications = $parametres->getNotification();
                      if (in_array("Changepassword", $notifications)) {
                          $notification = true;
                      } else {
                          $notification = false;
                      }
                      $body = $this->renderView('emails/changepassword.html.twig', array(
                          'user'=>$user,
                          'parametres'=>$parametres,
                      ));
                      $event = new ChangepasswordEndEvent($notification, $user->getFullname().': '.$translator->trans("New password registered"), $body, $user);
                      // On déclenche l'évènement
                      $dispatcher->dispatch(Events::end_changepassword, $event);
                      $em->persist($user);
                      $em->flush();
                      return $this->redirectToRoute('homepage');
                  }//fin de if submitted*/
                  $vue = 'security/changepassword.html.twig';
                  $habilitation = '';
                  return $this->render($vue, array(
                      'vue'=>$vue,
                      'habilitation'=>$habilitation,
                      'titre'=>$titre,
                      'user'=>$user,
                      'form' => $form->createView(),
                      ));
              }

          5. Je précise que le code ci-dessus n'a pas été nettoyé des aspects fonctionnels propres à mes sites, notamment l'envoi d'un email de confirmation sous condition et le déclenchement d'un  évènement en fin de procédure. Mais je pense vous sera possible de trier ce surplus :)

          6. Je n'alourdis pas la présente réponse par la procédure concernant le changement de profil par son user mais si nécessaire et sur demande elle pourra aussi faire l'objet d'un prochain post.

          -
          Edité par CarréDas1 14 décembre 2018 à 4:46:24

          • Partager sur Facebook
          • Partager sur Twitter
            14 décembre 2018 à 10:11:14

            Merci,

            J'avais pas du tout pensé à faire une entity pour changer le mot de passe.

            Ça aurait pu être merveilleux, mais.... Toujours le même problème de l'ancien mot de passe incorrect. Pourtant, quand je fais mes différents test (recuperation de l'ancien mot de passe User comparé au mot de passe saisi) tout à l'air correct. Mes mots de passe sont similaire !

            le 

            dump($passwordEncoder->isPasswordValid($user,'azerty',$user->getSalt()));

            me ramène true !!

            c'est au moment du $form->isValid() que ça pose problème, tout le code en dessous de ce if ne fonctionne pas !

            Du coup voilà mon nouveau controlleur : 

            /**
                 * @Route("/identifiant", name="identifiant")
                 */
                public function updateIdentifiant(Request $request, UserPasswordEncoderInterface $passwordEncoder)
                {
                    // 1) edit users
                    $em = $this->getDoctrine()->getManager();
            
                    $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
            
                    $user=$this->getUser();
            
            //        $ur=$em->getRepository(User::class);
            //
            //        $oldPassword = $user->getPassword();
            //
            //        var_dump($oldPassword);
                    var_dump($passwordEncoder->isPasswordValid($user,'azerty',$user->getSalt())); // renvoie true
            
                    $change = new ChangePassword();
            
                    $form = $this->createForm(ChangePasswordType::class, $change)
                                ->add('save', SubmitType::class, ['label' => "Mettre à jour"]);
            
                    // 2) handle the submit (will only happen on POST) La barre de debug Symfony me dit bien que c'est du post
                    $form->handleRequest($request);
                    if ($form->isSubmitted() && $form->isValid()) { //Là ça rentre pas
            
                        var_dump("submit");
            
                        $password = $passwordEncoder->encodePassword($user, $change->getPlainPassword());
            
                        $user->setPassword($password);
            
                        $em->persist($user);
                        $em->flush();
            
                        return $this->redirectToRoute('accueil');
                    }//fin de if submitted*/
            
                    return $this->render('identifiant/identifiant.html.twig', array(
                        'form' => $form->createView(),
                    ));
                }

            J'ai bien simplifier le code pour avoir seulement le nécessaire au changement de mot de passe, peut-être que j'ai enlevé quelque chose qu'il ne fallait pas 

            EDIT : En fait ça a marché, j'ai pas compris à quel moment j'ai aps vu que le mot de passe avait changé haha, merci beaucoup CarréDas1 !

            -
            Edité par VincentBoulard2 14 décembre 2018 à 10:18:05

            • Partager sur Facebook
            • Partager sur Twitter

            Symfony 4.2 problème lors du reset du mot de passe

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown