Home > Net >  How to create different the authentication error message in Symfony 5.4?
How to create different the authentication error message in Symfony 5.4?

Time:04-13

By default, it shows error "Invalid credentials.". I've already seen answers like "Go to translations, create security.en.yaml and type this:

# translations/security.en.yaml
'Invalid credentials.': 'Invalid email or password'

But how to create different errors? For example, "Invalid password" when password is wrong and "Email does not exists" when email is wrong. How to do it?

CodePudding user response:

you must create custom authorization and exceptions.

example: config/packages/security.yaml

security:
    enable_authenticator_manager: true
    ...
    providers: 
    ...
    firewalls:
        ...
        client:
            pattern: ^/
            custom_authenticators:
                - App\Security\ClientLoginFormAuthenticator
            logout:
                path: store.account.logout
                target: store.home
    access_control:
        ...

src/Security/ClientLoginFormAuthenticator.php

<?php
declare(strict_types=1);

namespace App\Security;

use App\Repository\UserRepository;
use App\Security\Exception\CustomException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use function in_array;

class ClientLoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
    private const LOGIN_ROUTE = 'store.account.login';

    public function __construct(private UserRepository $userRepository, private UrlGeneratorInterface $urlGenerator)
    {}

    public function supports(Request $request): bool
    {
        return self::LOGIN_ROUTE === $request->attributes->get('_route')
            && $request->isMethod('POST');
    }

    public function authenticate(Request $request): Passport
    {
        $password = $request->request->get('_password');
        $username = $request->request->get('_username');
        $csrfToken = $request->request->get('_csrf_token');

        return new Passport(
            new UserBadge($username, function ($userIdentifier) {
                $user = $this->userRepository->findOneBy(['email' => $userIdentifier]);
                if ($user && in_array('ROLE_CLIENT', $user->getRoles(), true)) {
                    return $user;
                }

                //next condition
                if($user && $user->getEmail() === '[email protected]') {
                    throw new CustomException();
                }

                throw new BadCredentialsException(); //default exception
            }),
            new PasswordCredentials($password),
            [new CsrfTokenBadge('authenticate', $csrfToken)]
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return null;
    }

    protected function getLoginUrl(Request $request): string
    {
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }
}

src/Security/Exception/CustomException.php

<?php
namespace App\Security\Exception;

use Symfony\Component\Security\Core\Exception\AuthenticationException;

class CustomException extends AuthenticationException
{
    /**
     * {@inheritdoc}
     */
    public function getMessageKey()
    {
        return 'My Message.';
    }
}

It works for me! :) Good luck!

  • Related