Mini-tutorial Silex Autenticación (III)

Written by Samuel de Ancos

En la anterior entrega (http://deancos.com/articles/mini-tutorial-silex-anadiendo-dependencias-twig-ii/) vimos como podíamos integrar fácilmente el sistema de plantilla twig con Silex, gracias a lo cual ya podíamos maquetar nuestros resultados mas fácilmente.

Hoy vamos a dar un nuevo paso en nuestro pequeño programa y vamos a preparar nuestra aplicación para poder autenticar y autorizar.

Vamos a añadir una nueva dependencia al proyecto: Security. Como vimos en los anteriores capítulos lo único que necesitamos es añadir la dependencia a nuestro composer.json:

   "symfony/security": "~2.3",

Una vez guardado el fichero tendremos algo como esto:

{
    "require": {
        "silex/silex": "~1.1",
        "twig/twig": ">=1.8,<2.0-dev",
        "symfony/twig-bridge": "~2.3",
        "symfony/security": "~2.3"
    }
}

Ahora podemos actualizar nuestro proyecto:

$ php composer.phar update

Bueno, ahora ya tenemos listas las dependencias que necesitamos para poder empezar a preparar nuestro entorno de seguridad.

Los primeros servicios que registramos son UrlGeneratorServiceProvider y SessionServiceProvider, ambos son servicios muy específicos que mas adelante utilizaremos, por ahora creo que sus nombre son bastante auto-explicativos.

Ya sabemos, en nuestro index.php registrar los servicios:

<?php
...
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\SessionServiceProvider());

Bueno, ahora vamos a registrar el servicio principal, SecurityServiceProvider, y lo configuraremos por defecto para poder hacer nuestras primeras pruebas. Por ahora como no tenemos aun base de datos podemos utilizar una configuración como la siguiente.

$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    "security.firewalls" => array(
        "admin" => array(
            "pattern" => "^/admin/",
            "form" => array("login_path" => "/login", "check_path" => "/admin/login_check"),
            "logout" => array("logout_path" => "/admin/logout"),
            "users" => array(
                "admin" => array("ROLE_ADMIN", "5FZ2Z8QIkA7UTZ4BYkoC+GsReLf569mSKDsfods6LYQ8t+a8EW9oaircfMpmaLbPBh4FOBiiFyLfuZmTSUwzZg=="),
            ),
        ),
    )
));

No entrare mucho a explicar como funciona la configuración pues en siguientes capítulos cuando lo integremos con la base de datos podremos explicarlo mas a fondo. Por ahora con saber que hemos configurado las rutas por defecto para poder hacer login/logout y que hemos creado un usuario admin es suficiente.

Ahora vamos a crear en nuestro controlador frontal una acción para hacer login:

$app->get("/login", function(Request $request) use ($app) {
    return $app["twig"]->render("login.html", array(
        "error"         => $app["security.last_error"]($request),
        "last_username" => $app["session"]->get("_security.last_username"),
    ));
});

Y su vista correspondiente con el formulario de login:

<form action="{{ path("admin_login_check") }}" method="post">
    {{ error }}
    <input type="text" name="_username" value="{{ last_username }}" />
    <input type="password" name="_password" value="" />
    <input type="submit" />
</form>

En este punto os podréis preguntar que significa y de donde sale esta linea en la vista: path(“admin_login_check”), pues efectivamente de uno de los servicios que antes registramos, exactamente de UrlGeneratorServiceProvider, que justamente se dedica a generar las urls que necesitamos de manera dinámica.

Bueno ya tenemos nuestra acción de login y su vista correspondiente.

Vamos a cambiar un poco lo que teníamos de capítulos anteriores para que tenga mas sentido con esta nueva funcionalidad, este seria nuestro nuevo controlador frontal:

<?php
require_once __DIR__."/../vendor/autoload.php";

use Symfony\Component\HttpFoundation\Request;

$app = new Silex\Application();
$app["debug"] = true;

$app->register(new Silex\Provider\TwigServiceProvider(), array("twig.path" => __DIR__."/views",));
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\SessionServiceProvider());
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    "security.firewalls" => array(
        "admin" => array(
            "pattern" => "^/admin/",
            "form" => array("login_path" => "/login", "check_path" => "/admin/login_check"),
            "logout" => array("logout_path" => "/admin/logout"),
            "users" => array(
                "admin" => array("ROLE_ADMIN", "5FZ2Z8QIkA7UTZ4BYkoC+GsReLf569mSKDsfods6LYQ8t+a8EW9oaircfMpmaLbPBh4FOBiiFyLfuZmTSUwzZg=="),
            ),
        ),
    )
));

$app->get("/", function () use ($app) {
    $user = $app["session"]->get("user");
    return $app["twig"]->render("index.html", array("user" => $user));
});

$app->get("/login", function(Request $request) use ($app) {
    return $app["twig"]->render("login.html", array(
        "error"         => $app["security.last_error"]($request),
        "last_username" => $app["session"]->get("_security.last_username"),
    ));
});

$app->get("/admin", function () use ($app) {
    return "Admin site";
});

$app->run();

Hemos añadido una nueva acción, /admin, para comprobar que funciona perfectamente el sistema de seguridad.


nota: la url /admin esta definida en la configuración de SecurityServiceProvider, es el valor de la clave pattern: “pattern” => “^/admin/“


También hemos cambiado un poco nuestra vista, index.html:

Hello {{ user }}, welcome!
<p>
    <a href="login">Login</a>
    <a href="{{ path("admin_logout") }}">Logout</a>
</p>

Una de las lineas nuevas del controlador frontal que aun no hemos explicado en la utilización de la clase request para recoger la petición:

Para utilizarlo lo único que tenemos que hacer es importarla y utilizarla en nuestra acción:

use Symfony\Component\HttpFoundation\Request;
$app->get("/login", function(Request $request) use ($app) {}

Ahora si entramos con nuestro navegador preferido a nuestra aplicación podremos probar y experimentar con el sistema de seguridad.

En próximas entregas entraremos mas a fondo en estos temas y otros también muy interesantes.