Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

form_login: El autentificador incorporado

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Las clases de autentificadores personalizados como ésta nos dan mucho control. Por ejemplo, imagina que, además de los campos de correo electrónico y contraseña, necesitaras un tercer campo, como un menú desplegable de "empresa"... y utilizaras ese valor -junto con el email - para consultar el User. Hacerlo aquí sería... ¡bastante sencillo! Coge el campocompany POST, úsalo en tu consulta personalizada y celébralo con nachos.

Pero un formulario de acceso es algo bastante común. Y por eso, Symfony viene con un autentificador de formularios de inicio de sesión incorporado que podemos... ¡simplemente usar!

Comprobando el Core FormLoginAuthenticator

Vamos a abrirlo y comprobarlo. Pulsa Shift+Shift y buscaFormLoginAuthenticator.

Lo primero que hay que observar es que extiende la misma clase base que nosotros. Y si te fijas en los métodos -hace referencia a un montón de opciones- pero en última instancia... hace lo mismo que nuestra clase: getLoginUrl() genera una URL a la página de inicio de sesión... y authenticate() crea un Passport con UserBadge,PasswordCredentials, un RememberMeBadge y un CsrfTokenBadge.

Tanto onAuthenticationSuccess como onAuthenticationFailure descargan su trabajo a otro objeto... pero si miraras dentro de ellos, verías que básicamente hacen lo mismo que nosotros.

Usar form_login

Así que vamos a usar esto en lugar de nuestro autentificador personalizado... lo que yo haría en un proyecto real a menos que necesite la flexibilidad de un autentificador personalizado.

En security.yaml, comenta el autentificador de nuestro cliente... y también comenta la configuración de entry_point:

security:
... lines 2 - 16
firewalls:
... lines 18 - 20
main:
... lines 22 - 23
#entry_point: App\Security\LoginFormAuthenticator
... lines 25 - 27
custom_authenticator:
# - App\Security\LoginFormAuthenticator
... lines 30 - 50

Sustitúyelo por una nueva clave form_login. Esto activa ese autentificador. Abajo, esto tiene un montón de opciones - te las mostraré en un minuto. Pero hay dos importantes que necesitamos: login_path: establecido a la ruta a tu página de inicio de sesión... así que para nosotros eso es app_login... y también el check_path, que es la ruta a la que se somete el formulario de inicio de sesión... que para nosotros también es app_login: nos sometemos a la misma URL:

security:
... lines 2 - 16
firewalls:
... lines 18 - 20
main:
... lines 22 - 24
form_login:
login_path: app_login
check_path: app_login
... lines 28 - 50

Configurando el punto_de_entrada como form_login

Y... ¡eso es todo para empezar! ¡Vamos a probarlo! Actualiza cualquier página y... ¡error! Un error que hemos visto:

Como tienes varios autentificadores en el firewall "principal", necesitas establecer "punto_de_entrada" en uno de ellos: o bien DummyAuthenticator, o bien form_login.

Ya he mencionado que algunos autenticadores proporcionan un punto de entrada y otros no. El autentificador remember_me no proporciona uno... pero nuestroDummyAuthenticator sí lo hace y también form_login. Su punto de entrada redirige a la página de inicio de sesión.

Así que, como tenemos varios, tenemos que elegir uno. Establece entry_point: como form_login:

security:
... lines 2 - 16
firewalls:
... lines 18 - 20
main:
... lines 22 - 23
entry_point: form_login
... lines 25 - 50

Personalizar los nombres de los campos del formulario de inicio de sesión

Ahora si refrescamos... genial: no hay error. Así que vamos a intentar iniciar la sesión. En realidad... Primero cerraré la sesión... eso sigue funcionando... luego entraré con abraca_admin@example.comcontraseña tada. Y... ¡ah! ¡Otro error!

La clave "_nombredeusuario" debe ser una cadena, dada NULL.

Y viene de FormLoginAuthenticator::getCredentials(). Vale, pues cuando utilices el built-in form_login, tienes que asegurarte de que algunas cosas están alineadas. Abre la plantilla de inicio de sesión: templates/security/login.html.twig. Nuestros dos campos se llaman email... y password:

... lines 1 - 4
{% block body %}
<div class="container">
<div class="row">
<div class="login-form bg-light mt-4 p-4">
<form method="post" class="row g-3">
... lines 10 - 15
<div class="col-12">
... line 17
<input type="email" name="email" id="inputEmail" class="form-control" required autofocus>
</div>
<div class="col-12">
... line 21
<input type="password" name="password" id="inputPassword" class="form-control" required>
</div>
... lines 24 - 34
</div>
</div>
</div>
{% endblock %}

Resulta que Symfony espera que estos campos se llamen _usernamey _password... por eso nos da este error: está buscando un parámetro POST _username... pero no está ahí. Afortunadamente, este es el tipo de cosas que puedes configurar.

Busca tu terminal favorito y ejecuta

symfony console debug:config security

para ver toda la configuración de seguridad actual. Desplázate hacia arriba... y buscaform_login... aquí está. Hay un montón de opciones que te permiten controlar el comportamiento de form_login. Dos de las más importantes son username_parametery password_parameter. Vamos a configurarlas para que coincidan con nuestros nombres de campo.

Así, en security.yaml añade username_parameter: email ypassword_parameter: password:

security:
... lines 2 - 16
firewalls:
... lines 18 - 20
main:
... lines 22 - 24
form_login:
... lines 26 - 27
username_parameter: email
password_parameter: password
... lines 30 - 53

Esto le dice que lea el parámetro email POST... y luego pasará esa cadena a nuestro proveedor de usuarios... que se encargará de consultar la base de datos.

Vamos a probarlo. Actualiza para volver a enviar y... ¡ya está! ¡Ya hemos iniciado la sesión!

La moraleja de la historia es la siguiente: usar form_login te permite tener un formulario de inicio de sesión con menos código. Pero mientras que usar una clase de autentificador personalizada es más trabajo... tiene una flexibilidad infinita. Así que, es tu elección.

A continuación: vamos a ver algunas otras cosas que podemos configurar en el formulario de inicio de sesión y a añadir una característica totalmente nueva: rellenar previamente el campo del correo electrónico cuando falle el inicio de sesión.

Leave a comment!

¡Este tutorial también funciona muy bien para Symfony 6!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.4.1 || ^8.0.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.3", // v3.3.0
        "composer/package-versions-deprecated": "^1.11", // 1.11.99.4
        "doctrine/annotations": "^1.0", // 1.13.2
        "doctrine/doctrine-bundle": "^2.1", // 2.6.3
        "doctrine/doctrine-migrations-bundle": "^3.0", // 3.1.1
        "doctrine/orm": "^2.7", // 2.10.1
        "knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
        "knplabs/knp-time-bundle": "^1.11", // v1.16.1
        "pagerfanta/doctrine-orm-adapter": "^3.3", // v3.3.0
        "pagerfanta/twig": "^3.3", // v3.3.0
        "phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
        "scheb/2fa-bundle": "^5.12", // v5.12.1
        "scheb/2fa-qr-code": "^5.12", // v5.12.1
        "scheb/2fa-totp": "^5.12", // v5.12.1
        "sensio/framework-extra-bundle": "^6.0", // v6.2.0
        "stof/doctrine-extensions-bundle": "^1.4", // v1.6.0
        "symfony/asset": "5.3.*", // v5.3.4
        "symfony/console": "5.3.*", // v5.3.7
        "symfony/dotenv": "5.3.*", // v5.3.8
        "symfony/flex": "^1.3.1", // v1.17.5
        "symfony/form": "5.3.*", // v5.3.8
        "symfony/framework-bundle": "5.3.*", // v5.3.8
        "symfony/monolog-bundle": "^3.0", // v3.7.0
        "symfony/property-access": "5.3.*", // v5.3.8
        "symfony/property-info": "5.3.*", // v5.3.8
        "symfony/rate-limiter": "5.3.*", // v5.3.4
        "symfony/runtime": "5.3.*", // v5.3.4
        "symfony/security-bundle": "5.3.*", // v5.3.8
        "symfony/serializer": "5.3.*", // v5.3.8
        "symfony/stopwatch": "5.3.*", // v5.3.4
        "symfony/twig-bundle": "5.3.*", // v5.3.4
        "symfony/ux-chartjs": "^1.3", // v1.3.0
        "symfony/validator": "5.3.*", // v5.3.8
        "symfony/webpack-encore-bundle": "^1.7", // v1.12.0
        "symfony/yaml": "5.3.*", // v5.3.6
        "symfonycasts/verify-email-bundle": "^1.5", // v1.5.0
        "twig/extra-bundle": "^2.12|^3.0", // v3.3.3
        "twig/string-extra": "^3.3", // v3.3.3
        "twig/twig": "^2.12|^3.0" // v3.3.3
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.0
        "symfony/debug-bundle": "5.3.*", // v5.3.4
        "symfony/maker-bundle": "^1.15", // v1.34.0
        "symfony/var-dumper": "5.3.*", // v5.3.8
        "symfony/web-profiler-bundle": "5.3.*", // v5.3.8
        "zenstruck/foundry": "^1.1" // v1.13.3
    }
}