Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

LoginListener con Symfony 2.6

1 de marzo de 2015

Hola a todos, espero me puedan ayudar.

Estoy realizando un inicio de sesión en Symfony 2.6, pero cada vez que me logueo me manda a la raíz de mi sitio (ej. http://mi_sitio.com/).

Me he guiado por otros ejemplos y me dicen que tengo que crear un Listener, pero no tengo idea de cómo hacerlo en Symfony 2.6. Con symfony 2.1 se manejaba un archivo LoginListener que recibe otros servicios secutity.context y router, pero en Symfony 2.6 ya no se usa security.context. Si me pueden ayudar aclarar mi duda. Gracias.


Respuestas

#1

Hola, y si usas en el formulario de login un <input> con la ruta que necesitas para dirigirte:

<input type="hidden" name="_target_path" value="/mi/ruta" />

Saludos!

@cristian_angulo

1 marzo 2015, 20:49
#2

@JuniorAguilar7 como te comenta @cristian_angulo, sólo tienes que añadir un <input> en el formulario de login o incluso puedes configurar la redirección en el propio archivo security.yml. No necesitas crear un listener a menos que la redirección que quieras hacer sea muy avanzada (por ejemplo redirigir a cada usuario a una página diferente).

Por otra parte, en Symfony 2.6 el servicio security.context se ha declarado obsoleto, pero todavía está disponible y puedes usarlo. Este servicio desaparecerá en Symfony 3.0 y será reemplazado por otros dos nuevos servicios: security.authorization_checker y security.token_storage.

@javiereguiluz

1 marzo 2015, 22:46
#3

Buenas, la doc oficial explica varias formas de hacerlo:

Allí mismo tienes otras opciones interesantes, por lo que puedes probar con ellas para lograr diferentes comportamientos.

Saludos!

@manuel_j555

1 marzo 2015, 23:09
#4

Muchas gracias por su ayuda. He leído la documentación pero no se qué estoy haciendo mal. Como dice Javier es lo que quiero hacer: redirigir a cada usuario a una página diferente.

# AppBundle/Resources/Config/services.yml
    login_listener:
        class: AppBundle\Listener\LoginListener
        arguments: ["@security.context", "@router"]
        tags:
            - { name: kernel.event_listener, event: security.interactive_login }
            - { name: kernel.event_listener, event: kernel.response }
// AppBundle/Listener/LoginListener.php
 
namespace AppBundle\Listener;
 
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\SecurityContext;
 
class LoginListener
{
    private $contexto, $router, $id = null;
 
    public function __construct(SecurityContext $context, Router $router)
    {
        $this->contexto = $context;
        $this->router = $router;
    }
 
    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) {
        $token = $event->getAuthenticationToken();
        $this->id = $token->getUser()->getId();
    }
 
    public function onKernelResponse(FilterResponseEvent $event) {
        if (null != $this->id) {
            if($this->contexto->isGranted('ROLE_ADMIN')) {
                $dashboard = $this->router->generate('admin_dashboard');
            } else if($this->contexto->isGranted('ROLE_USER')) {
                $dashboard = $this->router->generate('user_dashboard');
            } else if($this->contexto->isGranted('ROLE_OPERADOR')) {
                $dashboard = $this->router->generate('operador_dashboard');
            }
 
            $event->setResponse(new RedirectResponse($dashboard));
            $event->stopPropagation();
        }
    }
}

Tengo ese código y lo que pasa es que me redirige es a www.mi_sitio.com/ no me manda a las rutas que le asigno. No se qué error estoy cometiendo o qué me falta configurar.

@JuniorAguilar7

2 marzo 2015, 2:18
#5

Buenas, te está faltando especificar el método a llamar en la definición del servicio, en los tags.

login_listener:
    class: AppBundle\Listener\LoginListener
    arguments: ["@security.context", "@router"]
    tags:
        - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
        - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }

Me parace raro que no te de ningún error el que no coloques el method en los tags.

Saludos!

@manuel_j555

2 marzo 2015, 2:52
#6

Hola @manuel_j555, ya intente lo que me dijiste, limpie cache, y aun sigue redirigiéndome a www.mi_sitio.com/. No se qué puede estar fallando.

@JuniorAguilar7

2 marzo 2015, 3:17
#7

El último else tiene una condición, por lo que debería ser entonces else if. Prueba a colocar unos die("Mensaje"); en alguno de los métodos para verificar si se están ejecutando o no al loguear.

@manuel_j555

2 marzo 2015, 3:43
#8

Ya corregí lo del else if. Coloqué los die() y al parecer no entra en ningún método del listener. No veo por ningún lado los mensajes. ¿a qué se deberá esto? La opción de @cristian_angulo me sirve a la perfección, pero solo funciona para una sola ruta.

@JuniorAguilar7

2 marzo 2015, 4:04
#9

Como dices que no se ejecuta ningún método, quizás el error se debe a que el servicio del login_listener definido en el archivo AppBundle/Resources/Config/services.yml que muestras en el comentario #4 no se está cargando.

Para confirmar o descartar este error, ejecuta el siguiente comando en la consola:

$ php app/console container:debug login_listener

Deberías ver la información de tu listener. Si no ves nada, prueba a ejecutar lo siguiente para ver todos los listener registrados en tu aplicación:

$ php app/console container:debug listener

@javiereguiluz

2 marzo 2015, 8:26
#10

Muchas gracias por la ayuda a todos... @javiereguiluz ejecuté los comandos y no estaba registrado mi servicio. Lo solucioné cambiando el código que estaba en AppBundle/Resources/Config/services.yml y lo coloque en App/config/services.yml y funciona de maravilla muchas gracias :) (y)

@JuniorAguilar7

2 marzo 2015, 14:34
#11

Ahora que ya sabemos cuál era la causa del problema, me gustaría explicar el problema con más detalle para cualquier persona que consulte esta pregunta en el futuro.

Las versiones modernas de Symfony (2.6 o superior) incluyen un archivo llamado app/config/services.yml donde las aplicaciones pueden definir sus servicios. Cualquier servicio definido en ese archivo está disponible automáticamente en la aplicación. ¿Por qué? Porque ese archivo services.yml se carga desde el archivo principal de configuración app/config/config.yml.

Cuando la aplicación tiene muchos servicios, algunos programadores prefieren no usar el archivo services.yml general y definen un archivo services.yml (o services.xml) en cada uno de sus bundles. Estos archivos se definen en src/NOMBRE_DEL_BUNDLE/Resources/config/ y a diferencia del archivo services.yml global, estos archivos no se cargan automáticamente.

Cada uno de los tus bundles tiene que decirle a la aplicación que dispone de un archivo que define servicios y que quieres cargarlos. Para ello, hay que crear un archivo de tipo "extensión del contenedor de inyección de dependencias". Si el bundle se encuentra en src/Acme/MiBundle/, hay que crear el siguiente archivo:

// src/Acme/MiBundle/DependenyInjection/AcmeMiBundleExtension.php
namespace Acme\MiBundle\DependencyInjection;
 
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
 
class AcmeMiBundleExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');
    }
}

@javiereguiluz

2 marzo 2015, 15:17
#12

Muchas gracias por la información.

@JuniorAguilar7

2 marzo 2015, 15:31