If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeUtilizar form_login
no es tan flexible como una clase de autentificador personalizada... aunque se pueden configurar muchas cosas.
Por ejemplo, ahora mismo, no comprueba nuestro token CSRF. Habilita eso diciendo enable_csrf: true
:
security: | |
... lines 2 - 16 | |
firewalls: | |
... lines 18 - 20 | |
main: | |
... lines 22 - 24 | |
form_login: | |
... lines 26 - 29 | |
enable_csrf: true | |
... lines 31 - 54 |
¡Eso es! En las opciones, cuando activas la protección CSRF, busca un campo oculto llamado _csrf_token
con la cadena authenticate
utilizada para generarlo. Afortunadamente, en nuestra plantilla, ya estamos utilizando ambas cosas... así que esto va a funcionar.
Y hay aún más formas de configurarlo. Recuerda: para obtener esta configuración, he ejecutado debug:config security
... que muestra tu configuración actual, incluyendo los valores por defecto. Pero aquí no se muestran todas las opciones. Para ver una lista completa, ejecutaconfig:dump security
.
symfony console config:dump security
En lugar de mostrar tu configuración actual, esto muestra una enorme lista de configuraciones de ejemplo. Esta es una lista mucho más grande... aquí está form_login
. Mucho de esto lo hemos visto antes... pero success_handler
y failure_handler
son nuevos. Puedes buscarlos en la documentación para aprender a controlar lo que ocurre tras el éxito o el fracaso.
Pero también, más adelante, vamos a conocer una forma más global de engancharse al proceso de éxito o fracaso registrando un oyente de eventos.
De todos modos, ya no vamos a utilizar nuestro LoginFormAuthenticator
, así que puedes eliminarlo.
Y... ¡Tengo buenas noticias! ¡El autentificador principal está haciendo una cosa que nuestra clase nunca hizo! En authenticate()
... llama a getCredentials()
para leer los datos POST. Déjame buscar "sesión"... ¡yup! Esto me llevó agetCredentials()
. De todos modos, después de coger el correo electrónico enviado - en este código que se almacena como $credentials['username']
- guarda ese valor en la sesión.
Lo hace para que, si falla la autenticación, podamos leerlo y rellenar previamente la casilla del correo electrónico en el formulario de acceso.
¡Vamos a hacerlo! Ve a nuestro controlador: src/Controller/SecurityController.php
. EsteAuthenticationUtils
tiene otro método útil. Pasa una nueva variable a la plantilla llamada last_username
-puedes llamarla last_email
si quieres- y ponla en $authenticationUtils->getLastUsername()
:
... lines 1 - 9 | |
class SecurityController extends AbstractController | |
{ | |
... lines 12 - 14 | |
public function login(AuthenticationUtils $authenticationUtils): Response | |
{ | |
return $this->render('security/login.html.twig', [ | |
... line 18 | |
'last_username' => $authenticationUtils->getLastUsername(), | |
]); | |
} | |
... lines 22 - 29 | |
} |
Una vez más, esto es sólo un ayudante para leer una clave específica de la sesión.
Ahora, en la plantilla - login.html.twig
- aquí arriba en el campo de correo electrónico, añadevalue="{{ last_username }} "
:
... 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" value="{{ last_username }}" required autofocus> | |
</div> | |
... lines 20 - 33 | |
</form> | |
</div> | |
</div> | |
</div> | |
{% endblock %} |
¡Genial! Si vamos a /login
... ¡ya está ahí por haber rellenado el formulario hace un minuto! Si introducimos un correo electrónico diferente... ¡sí! Eso también se pega.
A continuación: volvamos a la autorización aprendiendo a denegar el acceso en un controlador... de varias maneras.
Hey @Soufiyane!
Are you referring to how to print the "last username" thing? If so, the 2 steps are:
1) In your custom authenticator, in authenticate()
, after reading the email, call:
$request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $credentials['username']);
2) In your controller, read that value in the same way as see in this chapter :).
Let me know if that helps!
Cheers!
Hi. I stayed with the custom login in my project. Can you show me how to add $authenticationUtils-> getLastUsername()
, in this case? In case without form_login
: it didn't work :)
Hey Leszek,
You only need to inject the service Symfony\Component\Security\Http\Authentication\AuthenticationUtils
into your Controller's method, or in case you need it in your authenticator, you can add another argument constructor and inject it there
Cheers!
// composer.json
{
"require": {
"php": ">=8.1",
"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
}
}
how can we implement this if we kept using the old
loginFormAuthonticator
on theonAuthenticationFailure
method?