Error in view : Symfony\Component\Security\Core\Exception\BadCredentialsException: The presented password cannot be empty.
in log: security.DEBUG: Authenticator does not support the request. {"firewall_name":"main","authenticator":"App\Security\AppCustomAuthenticator"} []
and: security.DEBUG: Authenticator does not support the request. {"firewall_name":"main","authenticator":"Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator"} []
in security.yaml:
security:
# https://symfony.com/doc/current/security/experimental_authenticators.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
App\Entity\User:
algorithm: auto
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
# 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
# used to reload user from session & other features (e.g. switch_user)
# used to reload user from session & other features (e.g. switch_user)
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
#provider: users_in_memory
custom_authenticators:
- App\Security\AppCustomAuthenticator
form_login:
# "login" is the name of the route created previously
login_path: login
check_path: login
failure_path: login
enable_csrf: true
username_parameter: _email
password_parameter: _password
target_path_parameter: go_to
logout:
path: logout
# where to redirect after logout
target: Accueil
invalidate_session: true
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
##ad a remember me option aut login
remember_me:
secret: '%kernel.secret%'
# ...
always_remember_me: true
# 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 }
in controller:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="login", methods={"GET","POST"})]
*
*/
public function index(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', [
'controller_name' => 'LoginController',
'last_email' => $lastUsername,
'error' => $error,
]);
}
/**
* @Route("/logout", name="logout", methods={"GET"})
*/
public function logout(): void//?Response
{
}
}
in UserRepository:
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
/**
* @method User|null find($id, $lockMode = null, $lockVersion = null)
* @method User|null findOneBy(array $criteria, array $orderBy = null)
* @method User[] findAll()
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
}
$user->setPassword($newHashedPassword);
$this->_em->persist($user);
$this->_em->flush();
}
// /**
// * @return User[] Returns an array of User objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->orderBy('u.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
public function findOneBySomeField($value): ?User
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
}
in twig: {% extends 'base.html.twig' %} {
% use "base.html.twig" with stylesheets as style_parent %}
{% block stylesheets %}
{{ block('style_parent') }}
<link rel="stylesheet" href="{{ asset('css/login-form.css') }}">
{% endblock %}
{% block title %}Se logger pour obtenir toutes les fonctionnalités{% endblock %}
{% block body %}
{% use "background_menu.html.twig" with header as parent_menu %}
{% block header %}
{{ block('parent_menu') }}
{% endblock %}
{% if error %}
<div >{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{% if app.user %}
<div >
{{ app.user.email }}, Vous êtes Connecté, <a href="{{ path('logout') }}" >Déconnexion</a>
</div>
{% endif %}
<form action="{{ path('login') }}" method="post">
<h1 >Connectez-vous</h1>
<div >
<div >
<label for="email">Email:</label>
<input type="text" id="email" name="_email" value="{% if last_email %}{{ last_email }}{% endif %}"/>
</div>
<div >
<label for="password">Password:</label>
<input type="password" id="_password" name="password"/>
</div>
{% if error %}
<div >{{ error }}</div>
{% endif %}
{# If you want to control the URL the user is redirected to on success #}
<input type="hidden" name="_target_path" value="{{ path('Accueil') }}"/>
<div >
<a href="{{ path('register')}}" >S'inscrire</a> ou <a href="#" >Mot de Passe oublié</a>
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<input type="hidden" name="go_to" value="{{ path('Accueil') }}"/>
<button type="submit" name="login">Connection</button>
</div>
</form>
<br><br><br><br>
{% use "footer.html.twig" with footer as parent_footer %}
{% block footer %}
{{ block('parent_footer') }}
{% endblock %}
{% endblock %}
in AppCustomAuthenticator:
// src/Security/AppCustomAuthenticator.php
namespace App\Security;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class AppCustomAuthenticator extends AbstractAuthenticator
{
private $router;
public function __construct(UrlGeneratorInterface $router)
{
$this->router = $router;
}
/**
* Called on every request to decide if this authenticator should be
* used for the request. Returning `false` will cause this authenticator
* to be skipped.
*/
public function supports(Request $request): ?bool
{
return $request->headers->has('X-AUTH-TOKEN');
}
public function authenticate(Request $request): PassportInterface
{
$apiToken = $request->headers->get('X-AUTH-TOKEN');
if (null === $apiToken) {
// The token header was empty, authentication fails with HTTP Status
// Code 401 "Unauthorized"
throw new CustomUserMessageAuthenticationException('No API token provided');
}
return new SelfValidatingPassport(new UserBadge($apiToken));
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
// on success, let the request continue
//return null;
return new RedirectResponse($this->router->generate('Accueil'));
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$data = [
// you may want to customize or obfuscate the message first
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
// or to translate this message
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
}
CodePudding user response:
I changed the input password for:
<input type="password" id="_password" name="_password"/>
now i have in log:
security.DEBUG: Authenticator does not support the request. {"firewall_name":"main","authenticator":"App\\Security\\AppCustomAuthenticator"} []
and the error twig:
Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException: Invalid CSRF token
CodePudding user response:
Now it was your answer:
<input type="password" id="_password" name="_password"/>
<input type="text" id="_email" name="_email" value="{% if last_email %}{{ last_email }}{% endif %}"/>
And after replace:
<input type="hidden" name="go_to" value="{{path('Accueil') }}"/>
by:
<input type="hidden" name="go_to" value="Accueil"/>
And in security.yaml:
form_login:
# "login" is the name of the route created previously
login_path: login
check_path: login
failure_path: login
enable_csrf: true
username_parameter: _email
password_parameter: _password
target_path_parameter: go_to