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,
));
}
source to share
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
source to share
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>
....
source to share