[Symfony 4] Utilisation encodage

a marqué ce sujet comme résolu.

Bonjour à tous !

Je viens vers vous car je fais face un problème dont je n’arrive pas à trouver la solution.

J’utilise Symfony 4 - je suis encore en phase d’apprentissage du framework - et j’essaie actuellement de mettre en place une simple authentification en utilisant la classe UserInterface.

L’inscription fonctionne très bien et le mot de passe crypté avec bcrypt est bien stocké dans la BDD. Je vous mets le code, au cas où :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
/**
 * @Route("/inscription", name="registration")
 */
public function register(Request $request, SessionInterface $session, UserPasswordEncoderInterface $encoder)
{
    $user = new User();

    //Création du formulaire
    $form = $this->createFormBuilder($user)
        ->add('username', TextType::class, array('label' => 'Pseudo'))
        ->add('password', PasswordType::class, array('label' => 'Mot de passe'))
        ->add('email', EmailType::class, array('label' => 'Adresse email'))
        ->add('register', SubmitType::class, array('label' => 'S\'inscrire'))
        ->getForm();

    $form->handleRequest($request);

    if($form->isSubmitted() && $form->isValid())
    {
        $user = $form->getData();

        //Sauvegarde des données dans la base
        $entity = $this->getDoctrine()->getManager();
        //Récupération du rôle par défaut du compte lors de l'inscription, à savoir, le rôle User
        $role = $entity->getRepository(Role::class)->findOneBy([ 'name' => 'User']);

        $passwordEncoded = $encoder->encodePassword($user, $user->getPassword());

        $user->setRoles($role);
        $user->setPassword($passwordEncoded);
        $entity->persist($user);
        $entity->flush();

        //Ajout du pseudo et du rôle dans la session
        $session->set('pseudo', $user->getUsername());
        $session->set('role', $user->getRoles()->getName());

        $this->addFlash(
            'notice', 'Inscription réussie'
        );

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

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

Par contre, impossible de mettre en place l’authentification malgré avoir regardé encore et encore dans la documentation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
/**
 * @Route("/connexion", name="connexion")
 */
public function connection(Request $request, SessionInterface $session, UserPasswordEncoderInterface $encoder)
{
    $user = new User();

    $form = $this->createFormBuilder($user)
        ->add('username', TextType::class, array('label' => 'Pseudo'))
        ->add('password', PasswordType::class, array('label' => 'Mot de passe'))
        ->add('connection', SubmitType::class, array('label' => 'Se connecter'))
        ->getForm();

    $form->handleRequest($request);

    if($form->isSubmitted() && $form->isValid())
    {
        $pseudo = $form->get('username')->getData();

        //Recherche dans la base de donnée s'il y a bien un compte
        $user = $this->getDoctrine()->getRepository(User::class)->findOneBy([
            'username' => $pseudo,
        ]);

        //S'il y a bien un compte avec le pseudo donné, vérification du mot de passe
        if($user)
        {
            if ($encoder->isPasswordValid($user, $form->get('password')->getData()))
            {
                $session->set('pseudo', $pseudo);
                $session->set('role', $user->getRoles()->getName());

                $this->addFlash(
                    'notice', 'Connecté'
                );

                return $this->redirectToRoute('index');
            }
            else
            {
                $this->addFlash(
                    'notice', $user->getPassword()
                );
            };
        }
        else
        {
            $this->addFlash(
                'notice', 'Pseudo et/ou mot de passe incorrecte'
            );
        }
    }

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

Ma méthode de connexion arrive à me trouver l’utilisateur via son username mais ensuite, pas moyen d’utiliser la fonction isPasswordValid() qui me renvoie toujours faux et je ne sais pas pourquoi. En regardant dans la documentation, il est indiqué qu’avec bcrypt, il ne faut pas utiliser de "salt" car il en a un intégré.

Du coup, j’avoue que je suis perdu. J’ai manqué quelque chose ?

Merci d’avance !

Salut !

Si je prends la version officielle pour Symfony 4.0, la méthode SecurityController::login (correspondant à ta méthode connection()) n’a apparemment pas la même signature, et est bien plus simple. Est-ce que tu ne serais pas en train de mettre du code normalement pour un provider dans le contrôleur ?

Ou tu tentes de t’affranchir de tout ça pour créer ton propre utilitaire d’authentification ?

+0 -0

Je n’utilise pas le Security Controller (que je ne savais même pas son existence). ^^

Je me suis basé sur ça et ça pour faire le formulaire d’inscription.

En fait, c’est un peu mon problème en cherchant : j’ai l’impression qu’il existe tellement de façon de faire et que la doc Symfony est assez mal organisée (de mon point de vue) surtout que sur Internet, il n’y a pas grand chose sur Symfony 4 (sûrement dû à sa "jeunesse")

Disons que c’est comme pour tout : quand tu sais ce que tu cherches, tu trouves ce dont tu as besoin  :p

Reprend la documentation du composant Security. En bas de cette page, tu as toute une série de liens vers des éléments relatifs à la sécurité, notamment le premier que tu as cité. Le premier que j’ai mentionné y est aussi.

+0 -0

Je vois mais je ne cherche pas à faire compliqué (pour le moment). ^^

Si je reprends cette page, il est écrit :

The $encoder object also has an isPasswordValid() method, which takes the User object as the first argument and the plain password to check as the second argument.

Donc, logiquement, cela ne devrait pas poser trop de problèmes. Et c’est là que je trouve que la doc est mal foutue : il n’y a aucune explication sur comment utiliser cette fameuse fonction. Et si je m’en réfère à la doc de l’API, il est bien écrit que le mot de passe doit être en clair.

Et j’ai vu des exemples sur Internet où cela fonctionnait.

Pourtant, par rapport à ce que la documentation que je t’ai fourni propose, je trouve que c’est déjà bien plus compliqué de descendre dans ce qui est probablement déjà existant  :lol:

Autant enfoncer une porte ouverte : tu dis que tu arrives bien à récupérer l’utilisateur, quid du mot de passe ?

+0 -0

Il faut vérifier. Ce n’est pas parce que ton code devrait fonctionner qu’il fonctionne, la preuve  :p

En revanche, je ne vois pas trop comment vérifier ça, vu que l’objet Encoder ne possède apparemment pas de méthode qui permette de récupérer ces informations.
J’ai xdebug et mon IDE pour faire du débogage pas à pas, ce qui me permettrait de voir les diverses valeurs et les méthodes exécutées, mais si tu ne l’as pas ou que ton IDE ne le permet pas, ça prendra un moment à paramétrer.

+0 -0

Il existe ceci, que j’avais déjà essayé :

1
2
3
<?php
$this->get('security.encoder_factory')->getEncoder($user)
?>

$this fait référence au contrôleur. Le problème est que j’ai le message d’erreur suivant :

The "security.encoder_factory" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.

J’ai cherché mais je n’ai pas trouvé la bonne réponse malgré des modifications selon ce que je trouvais. &gt;_&lt;

Oui et non.
Pourquoi vouloir récupérer l’encodeur avec $this->get('security.encoder_factory')->getEncoder($user) alors que dans les paramètres de la méthode connection(), tu as UserPasswordEncoderInterface $encoder qui devrait te retourner la même chose ? Dans le cas où tu veux juste voir quel encodeur c’est exactement (ne pas oublier que d’un côté tu attends le résultat d’une méthode d’usine, de l’autre une implémentation d’un interface), les deux méthodes (si la première ne gênait pas à cause du service privé) devraient retourner la même chose (soit une classe ayant lien avec ce que tu as défini dans security.yaml), donc tu peux très bien voir ce qu’est $encoder tel que récupéré en paramètre de la méthode…

+0 -0

Je suis d’accord. Je crois que j’ai mal compris ta question précédente. ^^

Je ne sais si c’est que tu voulais mais j’ai fait un print_r de la variable $encoder et voilà ce qu’elle m’affiche :

Symfony\Component\Security\Core\Encoder\UserPasswordEncoder Object ( [encoderFactory:Symfony\Component\Security\Core\Encoder\UserPasswordEncoder:private] => Symfony\Component\Security\Core\Encoder\EncoderFactory Object ( [encoders:Symfony\Component\Security\Core\Encoder\EncoderFactory:private] => Array ( [App\Entity\User] => Array ( [class] => Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder [arguments] => Array ( [0] => 13 ) ) ) ) )

OK, au moins on voit que Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder apparaît bien quelque part. Reste à comprendre ce qui ne passe pas.

Sans outils, je te conseillerais de faire une copie "de sauvegarde" du fichier contenant la classe Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder, et dans la méthode isPasswordValid, tu ajoutes des éléments de débogage pour déjà voir si les valeurs utilisées par password_verify() sont valables.

Après, si password_verify() ne retourne pas true, c’est soit parce que le mot de passe n’est vraiment pas le bon, soit il y a un souci avec l’agrégat du mot de passe en base de données — si tu pouvais nous le montrer en entier, d’ailleurs, juste pour vérifier qu’il ait la bonne tête pour un agrégat bcrypt, merci d’avance.

+0 -0

Tu es sûr du * au début du mot de passe ? Parce que ça ne me paraît pas normal, sauf erreur ça devrait commencer par un $.

Edit

Au temps pour moi, c’est MathJax qui me jouait des tours. Dans le cas de chaînes de caractères qui contiennent plusieurs $, utilise le code inline, entouré de `.

Mais regarde avec xdebug et PhpStorm, tu devrais pouvoir mieux voir s’il y a quelque chose qui ne fonctionne pas.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte