无效的凭据身份验证问题symfony 4

时间:2019-05-06 20:53:19

标签: php symfony symfony4

从symfony 4开始,我想创建一个简单的身份验证表单。我创建了一个User类(标识符是电子邮件字段,而不是“ Username”,我创建了一个类控制器并配置了security.yml文件。

但是,当我进入表单页面并尝试登录(填写电子邮件/密码字段并单击“提交”按钮)时,出现错误“无效的凭据”。

security.yaml

    encoders:
        App\Entity\User:
            algorithm: argon2i


    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: /logout


        #ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/profile, roles: ROLE_USER }

user.php

<?php

namespace App\Entity;


use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @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",length=255)
     */
    private $password;

    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 getAdresse(): ?string
    {
        return $this->adresse;
    }

    public function setAdresse(?string $adresse): self
    {
        $this->adresse = $adresse;

        return $this;
    }

    public function getTelephone(): ?string
    {
        return $this->telephone;
    }

    public function setTelephone(?string $telephone): self
    {
        $this->telephone = $telephone;

        return $this;
    }

    public function getSexe(): ?string
    {
        return $this->sexe;
    }

    public function setSexe(?string $sexe): self
    {
        $this->sexe = $sexe;

        return $this;
    }

    /**
     * @return Collection|Eleve[]
     */
    public function getElevesUser1(): Collection
    {
        return $this->elevesUser1;
    }

    public function addElevesUser1(Eleve $elevesUser1): self
    {
        if (!$this->elevesUser1->contains($elevesUser1)) {
            $this->elevesUser1[] = $elevesUser1;
            $elevesUser1->setUsertuteur1($this);
        }

        return $this;
    }

    public function removeElevesUser1(Eleve $elevesUser1): self
    {
        if ($this->elevesUser1->contains($elevesUser1)) {
            $this->elevesUser1->removeElement($elevesUser1);
            // set the owning side to null (unless already changed)
            if ($elevesUser1->getUsertuteur1() === $this) {
                $elevesUser1->setUsertuteur1(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection|Eleve[]
     */
    public function getElevesuser2(): Collection
    {
        return $this->elevesuser2;
    }

    public function addElevesuser2(Eleve $elevesuser2): self
    {
        if (!$this->elevesuser2->contains($elevesuser2)) {
            $this->elevesuser2[] = $elevesuser2;
            $elevesuser2->setUsertuteur2($this);
        }

        return $this;
    }

    public function removeElevesuser2(Eleve $elevesuser2): self
    {
        if ($this->elevesuser2->contains($elevesuser2)) {
            $this->elevesuser2->removeElement($elevesuser2);
            // set the owning side to null (unless already changed)
            if ($elevesuser2->getUsertuteur2() === $this) {
                $elevesuser2->setUsertuteur2(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection|profClasse[]
     */
    public function getProfsClasse(): Collection
    {
        return $this->profsClasse;
    }

    public function addProfsClasse(profClasse $profsClasse): self
    {
        if (!$this->profsClasse->contains($profsClasse)) {
            $this->profsClasse[] = $profsClasse;
            $profsClasse->setUser($this);
        }

        return $this;
    }

    public function removeProfsClasse(profClasse $profsClasse): self
    {
        if ($this->profsClasse->contains($profsClasse)) {
            $this->profsClasse->removeElement($profsClasse);
            // set the owning side to null (unless already changed)
            if ($profsClasse->getUser() === $this) {
                $profsClasse->setUser(null);
            }
        }

        return $this;
    }


    public function getCategorie(): ?Categorie
    {
        return $this->categorie;
    }

    public function setCategorie(?Categorie $categorie): self
    {
        $this->categorie = $categorie;

        return $this;
    }


}

securityController

<?php

namespace App\Controller;

use App\Entity\User;
use App\Security\LoginFormAuthenticator;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityManager;
use App\Form\RegistrationType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class SecurityController extends AbstractController
{
    /**
     * @Route("/login", name="app_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]);
    }


    /**
     * @Route("/registration", name="registration")
     */

    public function registration(Request $request, EntityManagerInterface $manager,GuardAuthenticatorHandler $guardAuthenticatorHandler,LoginFormAuthenticator $loginFormAuthenticator, UserPasswordEncoderInterface $passwordEncoder)
    {
        //obtenir une instance de User (vide)
        $user = new User();
        //relier l'instance $user avec notre formulaire pour la remplir
        $form = $this->createForm(RegistrationType::class,$user);
        // analyser la requête HTTP


        if ($form->handleRequest($request)->isSubmitted() && $form->isValid()) {
            $passwordEncoder = $passwordEncoder->encodePassword($user, $user->getPassword());
            $user->setPassword($passwordEncoder);
            $user->setRoles(['ROLE_ADMIN']);
            $manager->persist($user);
            $manager->flush();
            //une fois inscription terminé, redirection vers la page login
            return $guardAuthenticatorHandler->authenticateUserAndHandleSuccess($user,
                $request,
                $loginFormAuthenticator,
                'main');
        }
        //je veux afficher ce fichier là et j'aimerais lui passer des variables
        //qu'il pourra utiliser
        return $this->render('security/registration.html.twig', [
            'form' => $form->createView()
        ]);
    }


registrationType

<?php

namespace App\Form;

use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
class RegistrationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email',EmailType::class)
            ->add('password', RepeatedType::class,['type' => PasswordType::class,
                'invalid_message' =>'Les mots de passes doivent être identiques',
                'required'=>true,
                'first_options'=>['label'=>'mot de passe'],
            'second_options'=>['label'=>'repeter mot de passe'],])

        ;

    }

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

login.html.twig

{% extends 'base.html.twig' %}

{% block title %}Log in!{% endblock %}

{% block body %}
<form method="post">
    {% if error %}
        <div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
    {% endif %}

    <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
    <label for="inputEmail" class="sr-only">Email</label>
    <input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" placeholder="Email" required autofocus>
    <label for="inputPassword" class="sr-only">Password</label>
    <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>

    <input type="hidden" name="_csrf_token"
           value="{{ csrf_token('authenticate') }}"
    >

    {#
        Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
        See https://symfony.com/doc/current/security/remember_me.html

        <div class="checkbox mb-3">
            <label>
                <input type="checkbox" name="_remember_me"> Remember me
            </label>
        </div>
    #}

    <button class="btn btn-lg btn-primary" type="submit">
        Sign in
    </button>
</form>
{% endblock %}



loginFormAuthenticator

namespace App\Security;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
    use TargetPathTrait;

    private $entityManager;
    private $urlGenerator;
    private $csrfTokenManager;
    private $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
    {
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    }

    public function supports(Request $request)
        //check si on est bien sur la page de login
    {
        return 'app_login' === $request->attributes->get('_route')
            && $request->isMethod('POST');
    }

    public function getCredentials(Request $request)
    {//recuperer les infos soumises par l'utilisateur
        $credentials = [
            'email' => $request->request->get('email'),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['email']
        );

        return $credentials;
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {//on recupère d'abord le token et on verifie sil est valable'
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) {
            throw new InvalidCsrfTokenException();
        }

        $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);

        if (!$user) {
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('Email could not be found.');
        }

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {//elle va aller prendre le password entré par le user et va le comparer
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {//une fois que l'on est bien connecté
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse($this->urlGenerator->generate('home'));

    }



  protected function getLoginUrl()
    {
        return $this->urlGenerator->generate('app_login');
    }
}

2 个答案:

答案 0 :(得分:1)

问题可能出在您的LoginFormAuthenticator中。 防护身份验证系统依赖于此类,其描述为here

此外,您可以拥有一个symfony表单来创建登录页面,而不是“好旧的html表单”。因此,除了定义普通的html外,您还可以通过标准form.html.twig

将表单输出为其他任何表单
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}

并在您的控制器中

    /**
     * @Route("/login", name="security-login")
     */
    public function login(Request $request, AuthenticationUtils $authenticationUtils): Response
    {
        if($this->isGranted('IS_AUTHENTICATED_FULLY'))
            return $this->redirectToRoute('index');
        // get the login error if there is one
        $error = $authenticationUtils->getLastAuthenticationError();
        // last username entered by the user
        $lastUsername = $authenticationUtils->getLastUsername();

        $data = [];
        $builder = $this->createFormBuilder($data, ['csrf_token_id' => 'authenticate']);
        $builder->add('username', TextType::class,[
            'label' => 'Benutzername'
        ])->add('password', PasswordType::class, [
            'label' => "Passwort"
        ])->add('save', SubmitType::class, [
            'label' => 'Anmelden'
        ]);
        $response = new Response('');
        $form = $builder->getForm();

        if($error){
            $response->setStatusCode(401);
            if($error instanceof BadCredentialsException){
                $form->get('password')->addError(new FormError("Das Passwort ist falsch."));
            } else if( $error instanceof CustomUserMessageAuthenticationException ){
                /** @see CustomAuthenticator::getUser() */
                if($error->getCode() === 1)
                    $form->get('username')->addError(new FormError("Der Nutzer existiert, ist aber deaktiviert. Kontaktieren Sie einen Administrator."));
                else if($error->getCode() === 0)
                    $form->get('username')->addError(new FormError("Der Nutzer ist unbekannt."));
            } else {
                $form->get('user')->addError(new FormError("Unerwarteter Fehler. Bitte kontaktieren Sie den risklytics-Support."));
            }

        }


        $form->handleRequest($request);

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

        }

        return $this->render('default/form.html.twig', [
            'form' => $form->createView(),
            'title' => 'Anmelden'], $response);
    }

答案 1 :(得分:0)

encoders:
    App\Entity\User:
        algorithm: argon2i

# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
    # used to reload user from session & other features (e.g. switch_user)
    app_user_provider:
        entity:
            class: App\Entity\User
            property: email

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: /logout


        #ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/profile, roles: ROLE_USER }

您已经声明了提供者app_user_provider:,但是在防火墙内的任何地方都没有使用它。因此,在main:中,尝试添加:

provider: app_user_provider

如果遇到其他问题,请尝试启用form_login:

form_login:
    check_path: LOGIN_PATH
    login_path: LOGIN_PATH