ReynierPM
ReynierPM

Reputation: 18660

Redirect from existent route to a new one

I'm trying to redirect if a user is not logged in (works with FOSUser and SonataAdmin) and calls either http://domain.com/app_dev.php (dev) or http://domain.com (prod) then I want in both cases redirect to /login so I wrote this config at app/routing.yml:

root:
    path: /
    defaults:
        _controller: FrameworkBundle:Redirect:urlRedirect
        path: /login
        permanent: true

That works but I have a problem since I have this in a controller:

/**
 * @param Request $request
 *
 * @return array
 * @Route("/", name="brand")
 * @Method("GET")
 * @Template()
 */
public function indexAction(Request $request)
{
    ....
}

Then when I try to call brand route as per example using a link like: http://domain.com/app_dev.php/?email=7x-xRFClkjw (dev) or http://domain.com/?email=7x-xRFClkjw (prod) I got redirected to /login. My best idea is to change my code into this:

/**
 * @param Request $request
 *
 * @return array
 * @Route("/bp", name="brand")
 * @Method("GET")
 * @Template()
 */
public function indexAction(Request $request)
{
    ....
}

And then redirect using a route to the new /bp instead to / for that function (this is mainly because users already has a tons of emails that had links as the previously shared and I can't change that). But I've not idea in how to write this rule in routing.yml because if I wrote this:

bp:
    path: /
    defaults:
        _controller: FrameworkBundle:Redirect:redirect
        route: brand
        permanent: true

I will end up with a redirect loop. I could change also how default route to /login is setup I just can't find the right documentation. The big idea behind this post is to setup default route for /. Can any give me some help on this?

As extra info this is part of my security.yml file:

firewalls:
    ...

    admin_area:
        pattern: ^/
        anonymous: ~
        form_login:
            provider: fos_userbundle
            csrf_provider: form.csrf_provider

            # the user is redirected here when they need to log in
            login_path: /login

            # submit the login form here
            check_path: /login_check

            # login success redirecting options (read further below)
            always_use_default_target_path: true
            default_target_path: /admin/dashboard
            target_path_parameter: _target_path
            use_referer: false
            failure_path: /admin/dashboard
            failure_forward: false
        logout:
            path:   /logout

UPDATE

Actually the code from @emmanuel-hdz-díaz give me another idea and I don't need to create a kernel listener or add to much code, simple by doing this at my controller:

if ($request->query->get('email')) {
    ...
} else {
    return $this->redirect($this->generateUrl('sonata_user_admin_security_login'));
}

I was able to redirect the user to the /login route.

Upvotes: 0

Views: 270

Answers (3)

user2268997
user2268997

Reputation: 1391

Throw a special exception, catch it in the kernel.request event, redirect from there. You have to create a custom exception that you can store your route in.e.g:

class RouteException extends \Exception{
    protected $route;

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

    public function getRoute() { return $this->route; }
}

Now create a listener that will generate a RedirectResponse when it detects this exception, e.g:

class RedirectExceptionListener{
  protected $router;

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

  public function onException(GetResponseForExceptionEvent $event){

    $e = $event->getException();

    if($e instanceof RouteException){

      $url = $this->router->generate($e->getRoute());

      $event->setResponse(
        new RedirectResponse($url);
      );
    }
  }
}

# the service definition
your_listener:
    class: RedirectExceptionListener
    arguments:
        - @router
    tags:
        - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

Note: you have to use the namespaces for the used classes.
This is basically what you can do to redirect from anywhere in your application, although it does seem like a smelly use of exceptions, so create a service Redirecter with a method redirect($route) that throws the exception for you, so the calling service will not know how the redirection is being done.The Redirecter can throw the exception or do anything required to redirect to the given route.
For more info on event listeners see Event Listeners.

Update: This is exactly how symfony redirects you to your login_path when you're not authenticated, see ExceptionListener

Upvotes: 1

Emmanuel HD
Emmanuel HD

Reputation: 191

Try this:

In your controller inside yourAction():

//

$usr = $this->get('security.context')->getToken()->getUser();

if( $usr == 'anon.' )
{
return $this->redirect($this>generateUrl('sonata_user_admin_security_login'));
}

//

Upvotes: 1

malcolm
malcolm

Reputation: 5542

Not sure if I understand, but you want to restrict access to whole site? In that case just simply change you security setting, never add redirect to login, because it always redirect to login even if use is logged in. Here is simple configuration example:

security:
    firewalls:
        main:
            pattern: ^/
            anonymous: true

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

Upvotes: 1

Related Questions