Search code examples
phpauthenticationerror-handlingsymfony4registration

Symfony 4 - onAuthenticationSuccess redirection when isVerified is false


I'm trying to keep user in the login page if his email address is not verified yet after registration and he tries to login in.

This is the User class:

    <?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * @ORM\Entity(repositoryClass=UserRepository::class)
 * @UniqueEntity(fields={"cin"}, message="CIN utilisé par un autre utilisateur!")
 * @UniqueEntity(fields={"email"}, message="Email utilisé par un autre utilisateur!")
 * @UniqueEntity(fields={"idScout"}, message="Identifiant Scout utilisé par un autre utilisateur!")
 */
class User implements UserInterface
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, nullable=true, 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=180, nullable=true, unique=true)
     */
    private $cin;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $prenom;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $nom;

    /**
     * @ORM\Column(type="string", length=180, nullable=true, unique=true)
     */
    private $idScout;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateNaissance;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $groupe;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $region;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $branche;

//    /**
//     * @ORM\Column(type="string", length=255, nullable=true)
//     */
//    private $niveauFormation;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $niveauEducation;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $profession;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $tel;

    /**
     * @ORM\Column(type="boolean")
     */
    private $isVerified = false;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $formationPrimaire;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateFormationPrimaire;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $formationPreliminaire;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateFormationPreliminaire;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $formationBadge;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateFormationBadge;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $M1;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $M2;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateM1;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateM2;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $M3;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateM3;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $S1;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateS1;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $S2;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateS2;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $S3;

    /**
     * @ORM\Column(type="date", nullable=true)
     */
    private $dateS3;

    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;
        return (string) $this->cin;
    }

    /**
     * @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 $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * Returning a salt is only needed, if you are not using a modern
     * hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
     *
     * @see UserInterface
     */
    public function getSalt(): ?string
    {
        return null;
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function getCin(): ?string
    {
        return $this->cin;
    }

    public function setCin(?string $cin): self
    {
        $this->cin = $cin;

        return $this;
    }

    public function getPrenom(): ?string
    {
        return $this->prenom;
    }

    public function setPrenom(?string $prenom): self
    {
        $this->prenom = $prenom;

        return $this;
    }

    public function getNom(): ?string
    {
        return $this->nom;
    }

    public function setNom(?string $nom): self
    {
        $this->nom = $nom;

        return $this;
    }

    public function getIdScout(): ?string
    {
        return $this->idScout;
    }

    public function setIdScout(?string $idScout): self
    {
        $this->idScout = $idScout;

        return $this;
    }

    public function getDateNaissance(): ?\DateTimeInterface
    {
        return $this->dateNaissance;
    }

    public function setDateNaissance(?\DateTimeInterface $dateNaissance): self
    {
        $this->dateNaissance = $dateNaissance;

        return $this;
    }

    public function getGroupe(): ?string
    {
        return $this->groupe;
    }

    public function setGroupe(?string $groupe): self
    {
        $this->groupe = $groupe;

        return $this;
    }

    public function getRegion(): ?string
    {
        return $this->region;
    }

    public function setRegion(?string $region): self
    {
        $this->region = $region;

        return $this;
    }

    public function getBranche(): ?string
    {
        return $this->branche;
    }

    public function setBranche(?string $branche): self
    {
        $this->branche = $branche;

        return $this;
    }

//    public function getNiveauFormation(): ?string
//    {
//        return $this->niveauFormation;
//    }
//
//    public function setNiveauFormation(?string $niveauFormation): self
//    {
//        $this->niveauFormation = $niveauFormation;
//
//        return $this;
//    }

    public function getNiveauEducation(): ?string
    {
        return $this->niveauEducation;
    }

    public function setNiveauEducation(?string $niveauEducation): self
    {
        $this->niveauEducation = $niveauEducation;

        return $this;
    }

    public function getProfession(): ?string
    {
        return $this->profession;
    }

    public function setProfession(?string $profession): self
    {
        $this->profession = $profession;

        return $this;
    }

    public function getTel(): ?string
    {
        return $this->tel;
    }

    public function setTel(?string $tel): self
    {
        $this->tel = $tel;

        return $this;
    }

    public function isVerified(): bool
    {
        return $this->isVerified;
    }

    public function setIsVerified(bool $isVerified): self
    {
        $this->isVerified = $isVerified;

        return $this;
    }

    public function getFormationPrimaire(): ?bool
    {
        return $this->formationPrimaire;
    }

    public function setFormationPrimaire(?bool $formationPrimaire): self
    {
        $this->formationPrimaire = $formationPrimaire;

        return $this;
    }

    public function getDateFormationPrimaire(): ?\DateTimeInterface
    {
        return $this->dateFormationPrimaire;
    }

    public function setDateFormationPrimaire(?\DateTimeInterface $dateFormationPrimaire): self
    {
        $this->dateFormationPrimaire = $dateFormationPrimaire;

        return $this;
    }

    public function getFormationPreliminaire(): ?bool
    {
        return $this->formationPreliminaire;
    }

    public function setFormationPreliminaire(?bool $formationPreliminaire): self
    {
        $this->formationPreliminaire = $formationPreliminaire;

        return $this;
    }

    public function getDateFormationPreliminaire(): ?\DateTimeInterface
    {
        return $this->dateFormationPreliminaire;
    }

    public function setDateFormationPreliminaire(?\DateTimeInterface $dateFormationPreliminaire): self
    {
        $this->dateFormationPreliminaire = $dateFormationPreliminaire;

        return $this;
    }

    public function getFormationBadge(): ?bool
    {
        return $this->formationBadge;
    }

    public function setFormationBadge(?bool $formationBadge): self
    {
        $this->formationBadge = $formationBadge;

        return $this;
    }

    public function getDateFormationBadge(): ?\DateTimeInterface
    {
        return $this->dateFormationBadge;
    }

    public function setDateFormationBadge(?\DateTimeInterface $dateFormationBadge): self
    {
        $this->dateFormationBadge = $dateFormationBadge;

        return $this;
    }

    public function getM1(): ?bool
    {
        return $this->M1;
    }

    public function setM1(?bool $M1): self
    {
        $this->M1 = $M1;

        return $this;
    }

    public function getM2(): ?bool
    {
        return $this->M2;
    }

    public function setM2(?bool $M2): self
    {
        $this->M2 = $M2;

        return $this;
    }

    public function getDateM1(): ?\DateTimeInterface
    {
        return $this->dateM1;
    }

    public function setDateM1(?\DateTimeInterface $dateM1): self
    {
        $this->dateM1 = $dateM1;

        return $this;
    }

    public function getDateM2(): ?\DateTimeInterface
    {
        return $this->dateM2;
    }

    public function setDateM2(?\DateTimeInterface $dateM2): self
    {
        $this->dateM2 = $dateM2;

        return $this;
    }

    public function getM3(): ?bool
    {
        return $this->M3;
    }

    public function setM3(?bool $M3): self
    {
        $this->M3 = $M3;

        return $this;
    }

    public function getDateM3(): ?\DateTimeInterface
    {
        return $this->dateM3;
    }

    public function setDateM3(?\DateTimeInterface $dateM3): self
    {
        $this->dateM3 = $dateM3;

        return $this;
    }

    public function getS1(): ?bool
    {
        return $this->S1;
    }

    public function setS1(?bool $S1): self
    {
        $this->S1 = $S1;

        return $this;
    }

    public function getDateS1(): ?\DateTimeInterface
    {
        return $this->dateS1;
    }

    public function setDateS1(?\DateTimeInterface $dateS1): self
    {
        $this->dateS1 = $dateS1;

        return $this;
    }

    public function getS2(): ?bool
    {
        return $this->S2;
    }

    public function setS2(?bool $S2): self
    {
        $this->S2 = $S2;

        return $this;
    }

    public function getDateS2(): ?\DateTimeInterface
    {
        return $this->dateS2;
    }

    public function setDateS2(?\DateTimeInterface $dateS2): self
    {
        $this->dateS2 = $dateS2;

        return $this;
    }

    public function getS3(): ?bool
    {
        return $this->S3;
    }

    public function setS3(bool $S3): self
    {
        $this->S3 = $S3;

        return $this;
    }

    public function getDateS3(): ?\DateTimeInterface
    {
        return $this->dateS3;
    }

    public function setDateS3(?\DateTimeInterface $dateS3): self
    {
        $this->dateS3 = $dateS3;

        return $this;
    }
}

And here is the onAuthenticationSuccess function code:

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }

        $role = $token->getUser()->getRoles()[0];
        $isVerified = $token->getUser()->isVerified();
        if($isVerified===true){
            if ($role==='ROLE_ADMIN') {
                return new RedirectResponse($this->urlGenerator->generate('dashboard'));
            }elseif ($role==='ROLE_CHEF'){
                return new RedirectResponse($this->urlGenerator->generate('home'));
            }
        }else{
$request->getSession()->set(Security::AUTHENTICATION_ERROR, "You are not verified. Check your emails.");
        }
        throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
    }

I also need to display an error message (with addFlash) in the login page. However, That didn't work.

So what's wrong in my code and how can I fix it? Any idea?


Solution

  • Instead of using onAuthenticationSuccess (when authentication mechanic is done) you can use checkCredentials:

    public function checkCredentials($credentials, UserInterface $user)
    {
        // common part
        if (!$this->encoder->isPasswordValid($user, $credentials['_password'])) {
            return false;
        }
    
        // your custom check
        if (!$user->isVerified()) {
            // and your message
            throw new CustomUserMessageAuthenticationException(
                'bla-bla-bla'
            );
        }
    
        return true;
    }