How to make a redirect in a listener

I am trying to redirect to Listener but it doesn't work.

My listener:

<?php
// AuthenticationListener.php

namespace Acme\UserBundle\Listener;

use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Routing\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;

class AuthenticationListener
{
    protected $router;

    public function __construct(Router $router)
    {
        $this->router = $router;
    }

    public function onAuthenticationFailure(AuthenticationFailureEvent $event)
    {
        if(preg_match("/m\/login/", $_SERVER['HTTP_REFERER'])){
            // var_dump('Hello'); die();
            return new RedirectResponse($this->router->generate('mobile_login'));
        }
    }

    public function onAuthenticationSuccess(InteractiveLoginEvent $event)
    {
        if(preg_match("/m\/login/", $_SERVER['HTTP_REFERER'])){
           return new RedirectResponse($this->router->generate('mobile_home'));
        }
    }
}

      

I need this because I have 2 login forms: one for PC, one for mobile. So if the user made a mistake with his login / skip, I need to display the correct / login or / m / login page.

My script works. If I uncomment var_dump('Hello');

I see "Hello". Everything works well except for my redirect. I have no idea why. I have no errors, symfony just doesn't care and redirects me to / login. Apparently this is normal, I am not alone with this problem, but I cannot find a solution. I just read somewhere I need a Dispatcher, but I don't know how it works.

If you have a solution, that would be great.

Edit

My UserBundle / [...] / service.yml

# authentication failure event listener
acme_user.security.authentication_failure_event_listener:
    class: Acme\UserBundle\Listener\AuthenticationListener
    arguments: [@router]
    tags:
        - { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure }

# authentication success event listener
acme_user.security.interactive_login_listener:
    class: Acme\UserBundle\Listener\AuthenticationListener
    arguments: [@router]
    tags:
        - { name: kernel.event_listener, event: security.interactive_login, method: onAuthenticationSuccess }

      

My UserBundle / [...] / routing.yml

mobile_login:
    pattern:  /m/login
    defaults: { _controller: AcmeUserBundle:Mobile:login }

      

Edit by Abdullah Arfak

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    role_hierarchy:
        ROLE_MODO:        ROLE_USER
        ROLE_ADMIN:       ROLE_MODO
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_MODO, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username

    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        mobile:
            pattern:  ^/m
            anonymous: ~
            form_login:
                check_path: /m/login_check
                login_path: /m/login
                default_target_path: /m/admin
            logout:
                path:   /m/logout
                target: /

        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_provider: form.csrf_provider
            logout:       true
            anonymous:    true
            switch_user:  true
            remember_me:
                key:      "%secret%"
                lifetime: 31536000
                path:     /
                domain:   ~

    always_authenticate_before_granting: true

    access_control:
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/m/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }

      

MobileController.php

<?php

namespace Acme\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContext;

class MobileController extends Controller
{

    public function loginAction(Request $request)
    {
        /** @var $session \Symfony\Component\HttpFoundation\Session\Session */
        $session = $request->getSession();

        // get the error if any (works with forward and redirect -- see below)
        if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
            $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
        } elseif (null !== $session && $session->has(SecurityContext::AUTHENTICATION_ERROR)) {
            $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
            $session->remove(SecurityContext::AUTHENTICATION_ERROR);
        } else {
            $error = '';
        }

        if ($error) {
            // TODO: this is a potential security risk (see http://trac.symfony-project.org/ticket/9523)
            $error = $error->getMessage();
        }
        // last username entered by the user
        $lastUsername = (null === $session) ? '' : $session->get(SecurityContext::LAST_USERNAME);

        $csrfToken = $this->container->has('form.csrf_provider')
            ? $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate')
            : null;

        return $this->render('AcmeUserBundle:Mobile:login.html.twig', array(
            'last_username' => $lastUsername,
            'error'         => $error,
            'csrf_token' => $csrfToken,
        ));
    }

      

+3


source to share


3 answers


you don't need to go through the "Listener", the best way is to go through security

security.yml:

firewalls:

    dev:
        pattern:  ^/(_(profiler|wdt)|css|images|js)/
        security: false

    mobile:
        pattern:  ^/m
        anonymous: ~
        form_login:
            check_path: /m/login_check
            login_path: /m/login
            default_target_path: /m/admin
        logout:
            path:   /m/logout
            target: /

    main:
        pattern:  ^
        anonymous: ~
        form_login:
            check_path: /login_check
            login_path: /login
            default_target_path: /admin
        logout:
            path:   /logout
            target: /


access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/m/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }

      



routing.yml:

mobile_login:
    pattern:  /m/login
    defaults: { _controller: AcmeUserBundle:Mobile:login  }

mobile_check_special:
    pattern:  /m/login_check

mobile_logout_special:
    pattern:  /m/logout

      

+1


source


try something like this, not tested:

security.yml:

...

firewalls:
    some_area:
        ...

        form_login:
            failure_handler: custom.security.authentication_failure_handler
            login_path: /login
            check_path: /login_check

        logout:
            path:   /logout
            target: /

...

      

AuthenticationFailureHandler.php



class AuthenticationFailureHandler extends DefaultAuthenticationFailureHandler
{

    private $router;

    public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null, RouterInterface $router)
    {
        parent::__construct($httpKernel, $httpUtils, $options, $logger);

        $this->router = $router;
    }

    ....

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {

        if(preg_match("/m\/login/", $_SERVER['HTTP_REFERER'])){
            return $this->httpUtils->createRedirectResponse($request, $this->router->generate('mobile_login'));
        }

        return parent::onAuthenticationFailure($request, $exception);
    }
}

      

config service:

....

<service id="custom.security.authentication_failure_handler" class="%custom.security.authentication_failure_handler.class%" public="false">
    <argument type="service" id="kernel" />
    <argument type="service" id="security.http_utils" />
    <argument type="collection" />
    <argument type="service" id="logger"  on-invalid="ignore" />
    <argument type="service" id="router" />
</service>
....

      

+1


source


Try to write your service declaration like this:

services:
myservice:
    class: My\MyBundle\MyService
    arguments: [ @router ]
    scope: request

      

I think you missed the scope property.

0


source







All Articles