Is it possible to apply validation constraints to a Symfony login form?
To me it looks like that won't work. I use Symfony 5.2
I have created a Symfony login form as described on the documentation page "https://symfony.com/doc/current/security/form_login_setup.html".
Now I would like to validate the form and have created the following constraints for this in "validation.yaml".
App \ Entity \ User:
properties:
username:
- NotBlank:
message: 'form.user.username.not_blank'
password:
- NotBlank:
message: 'form.user.password.not_blank'
Unfortunately the constraints are ignored.
If I leave the username and password fields blank, I get a message that the login failed. In such a case, I would like to receive the constraint message that the username and password cannot be empty.
I didn't get any further during my research on the Internet.
Could it be that no validation constraints can be used in a Symfony login form?
Has anyone of you successfully set up validation constraints in a Symfony 5 login form and can you give me a tip on what to look out for?
I stumbled upon a similar issue - and used the following solution:
Since the authentification happens before the regular form validation I implemented a custom validation in the 'authenticate' method of my LoginFormAuthenticator:
public function authenticate(Request $request): PassportInterface
{
$credentials = $request->get('login');
<snip>
$errors = $this->validateCredentials($credentials);
if (0 !== $errors->count()) {
throw new AuthenticationException();
}
return new Passport(
new UserBadge($credentials['email']),
new PasswordCredentials($credentials['password']),
[
new CsrfTokenBadge('login_token', $credentials['_csrf_token']),
new RememberMeBadge(),
]
);
}
The validateCredentials method which stores the $error-object in the session:
public function validateCredentials($credentials) {
$constraints = new Assert\Collection([
'fields' => [
'email' =>
new Assert\Sequentially([
new Assert\NotBlank([
'message' => 'login.email.not_blank'
]),
new Assert\Email([
'message' => 'login.email'
])
]),
<snip>
],
'allowExtraFields' => true
]);
$errors = $this->validator->validate(
$credentials,
$constraints
);
if (0 !== $errors->count()) {
$this->session->set('login-errors', $errors);
} else {
$this->session->remove('login-errors');
}
return $errors;
}
The SecurityController fetches the $error-object from the session and adds the respective errors to the login form:
$loginForm = $this->createForm(LoginType::class, $formData);
$loginErrors = $request->getSession()->get('login-errors');
if ($loginErrors) {
foreach ($loginErrors as $error) {
$propertyPath = trim($error->getPropertyPath(), '[]');
$errorMessage = $error->getMessage();
$loginForm->get($propertyPath)->addError(new FormError($errorMessage));
}
}
Most likely not the best approach - but it does the job reasonably well and it's only the login form that makes this extra validation step necessary.