Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Construir un formulario de inicio de sesión

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Hay muchas maneras de permitir que tus usuarios se conecten... una de ellas es un formulario de conexión que carga a los usuarios desde la base de datos. Eso es lo que vamos a construir primero.

La forma más sencilla de construir un sistema de formulario de acceso es ejecutando un comandosymfony console make:auth. Eso generará todo lo que necesitas. Pero como queremos aprender realmente la seguridad, vamos a hacerlo paso a paso... sobre todo a mano.

Antes de que empecemos a pensar en la autenticación del usuario, primero tenemos que construir una página de inicio de sesión, que... si lo piensas... ¡no tiene nada que ver con la seguridad! Es sólo una ruta, un controlador y una plantilla normales de Symfony que renderizan un formulario. Vamos a hacer un poco de trampa para hacer esto. Ejecuta:

symfony console make:controller

Respuesta SecurityController. ¡Genial! Ve a abrir la nueva clase:src/Controller/SecurityController.php:

... lines 1 - 2
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class SecurityController extends AbstractController
{
/**
* @Route("/security", name="security")
*/
public function index(): Response
{
return $this->render('security/index.html.twig', [
'controller_name' => 'SecurityController',
]);
}
}

Aquí no hay nada demasiado sofisticado. Vamos a personalizarla para que sea una página de inicio de sesión: establece la URL como /login, llama a la ruta app_login y cambia el nombre del método a login():

... lines 1 - 8
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="app_login")
*/
public function login(): Response
{
... line 16
}
}

Para la plantilla, llámala security/login.html.twig... y no pases ninguna variable por ahora:

... lines 1 - 8
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="app_login")
*/
public function login(): Response
{
return $this->render('security/login.html.twig');
}
}

Abajo, en el directorio templates/, abre templates/security/... y cambia el nombre de la plantilla a login.html.twig:

{% extends 'base.html.twig' %}
{% block title %}Hello SecurityController!{% endblock %}
{% block body %}
<style>
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>
<div class="example-wrapper">
<h1>Hello {{ controller_name }}! ✅</h1>
This friendly message is coming from:
<ul>
<li>Your controller at <code><a href="{{ '/Users/weaverryan/Sites/knp/knpu-repos/symfony5/src/Controller/SecurityController.php'|file_link(0) }}">src/Controller/SecurityController.php</a></code></li>
<li>Your template at <code><a href="{{ '/Users/weaverryan/Sites/knp/knpu-repos/symfony5/templates/security/index.html.twig'|file_link(0) }}">templates/security/index.html.twig</a></code></li>
</ul>
</div>
{% endblock %}

Para empezar, voy a sustituir completamente esta plantilla y a pegar una nueva estructura: puedes copiarla del bloque de código de esta página:

{% extends 'base.html.twig' %}
{% block title %}Log In!{% endblock %}
{% 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">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<div class="col-12">
<label for="inputEmail">Email</label>
<input type="email" name="email" id="inputEmail" class="form-control" required autofocus>
</div>
<div class="col-12">
<label for="inputPassword">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" required>
</div>
<div class="col-12">
<button class="btn btn-lg btn-primary float-end" type="submit">
Sign in
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

Aquí no hay nada del otro mundo: extendemos base.html.twig, anulamos el bloque title... y tenemos un formulario que envía un POST de vuelta a /login. No tiene un atributo action, lo que significa que se envía de vuelta a esta misma URL. El formulario tiene dos campos -de entrada name="email" y de entrada name="password" - y un botón de envío... todo ello con clases de Bootstrap 5 para que tenga un buen aspecto.

Vamos a añadir un enlace a esta página desde base.html.twig. Busca el registro. Genial. Justo antes de esto, añade un enlace con {{ path('app_login') }}, que diga "Log In"... y dale algunas clases para que se vea bien:

<!DOCTYPE html>
<html>
... lines 3 - 14
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light px-1">
<div class="container-fluid">
... lines 18 - 26
<div class="collapse navbar-collapse" id="navbar-collapsable">
... lines 28 - 33
<a class="nav-link text-black-50" href="{{ path('app_login') }}">Log In</a>
<a href="#" class="btn btn-dark">Sign up</a>
</div>
</div>
</nav>
... lines 39 - 43
</body>
</html>

¡Vamos a comprobarlo! Actualiza la página de inicio... y haz clic en el enlace. ¡Hola página de inicio de sesión!

Y por supuesto, si rellenamos el formulario y lo enviamos... ¡no pasa absolutamente nada! Tiene sentido. Se envía de nuevo a /login... pero como todavía no tenemos ninguna lógica de procesamiento de formularios... la página simplemente se vuelve a presentar.

Así que lo siguiente: vamos a escribir ese código de procesamiento. Pero... ¡sorpresa! No vivirá en el controlador. Es hora de crear un autentificador y aprender todo sobre los cortafuegos de Symfony.

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
    }
}