0

Good evening, How is it possible to "auto-redirect" a user to the /account area, when he has the role e.g. ROLE_USER, so when he is authenticated / has logged in ? (Not anonymously)

I want to prevent the user to get access to the "standard" fos userbundle pages :

The "login form", "registration form" and "password reset" form,

when he is logged in That doesn't make sense for me if the user is already logged in and can log in a second time or reset his password or register again..

What is the best approach to handle that?

Regards

nova.cp
  • 455
  • 1
  • 9
  • 22
  • 1
    Is this what you are looking for? http://stackoverflow.com/questions/20190289/fosuserbundle-how-to-redirect-alrady-logged-in-users-when-trying-to-access-the – Milan van Schaik Nov 25 '14 at 00:29
  • You could do something like I answered here (http://stackoverflow.com/a/24310957/1791606) with the `FOSUserEvents::REGISTRATION_INITIALIZE` event added although this wouldn't help for the password rest as it doesn't create an event. The best way would be to listen to the `kernel.controller` event for those 3 controllers and if the user is logged in throw an exception that you could then catch in the `kernel.exception` event to then redirect. When I have more time I could elaborate further. – qooplmao Nov 25 '14 at 10:44
  • Hi Milan. I looked up the link, it's the exact approach i wrote to Alex's answer too :D (didn't read your article before). As your comment would help the most for people having the same issue, i should accept it as the correct answer (don't know how to accept comments as a correct answer). Thanks. @Qoop: Your answer is interesting too, im gonna have a look at it.:) – nova.cp Nov 25 '14 at 11:23

2 Answers2

1

Expanding on my answer in the comments.

The best approach that I can think off would be to listen for the kernel.controller event. Then in this event check whether the controller is in your list of blacklisted controller to decide whether or not to forward your user by way of exception.

EventSubscriber

This will listen for the kernel.controller event. It will then check whether the controller is one of the 3 FOSUserBundle controller that you want to miss if the user is logged in. If the controller is one of those then an exception is thrown which is then caught by the kernel.exception event. If the exception is the one specified then you forward the user to the route that you state in the redirect response.

namespace Acme\UserBundle\EventSubscriber;

use Acme\UserBundle\Exception\FOSUserRedirectException;
use FOS\UserBundle\Controller\RegistrationController as FOSRegistrationController;
use FOS\UserBundle\Controller\ResettingController as FOSResettingController;
use FOS\UserBundle\Controller\SecurityController as FOSSecurityController;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;

class FOSUserRedirectSubscriber implements EventSubscriberInterface
{
    protected $securityContext;

    protected $router;

    public function __construct(
        SecurityContextInterface $securityContext,
        UrlGeneratorInterface $router
    ) {
        $this->securityContext = $securityContext;
        $this->router = $router;
    }

    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::CONTROLLER    => 'onKernelController',
            KernelEvents::EXCEPTION     => 'onKernelException',
        );
    }

    /**
     * Check to see whether current user is logged in
     * If controller is one of specified throw FOSUserRedirectException
     *
     * @param FilterControllerEvent $event
     * @throws FOSUserRedirectException
     */
    public function onKernelController(FilterControllerEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType() ||
            !$this->securityContext->isGranted('ROLE_USER')
        ) {
            return;
        }

        $controller = $event->getController();

        if ($controller[0] instanceof FOSRegistrationController ||
            $controller[0] instanceof FOSResettingController ||
            $controller[0] instanceof FOSSecurityController
        ) {
            throw new FOSUserRedirectException();
        }
    }

    /**
     * If user is logged in but has loaded one of the specified
     * FOSUserBundle controllers
     *
     * @param GetResponseForExceptionEvent $event
     */
    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $exception = $event->getException();

        if (!$exception instanceof FOSUserRedirectException) {
            return;
        }

        $url = $this->router->generate('**THE_ROUTE_YOU_WISH_TO_REDIRECT_TO**');
        $response = new RedirectResponse($url);

        $event->setResponse($response);
    }
}

Exception

namespace Acme\UserBundle\Exception;

class FOSUserRedirectException extends \Exception
{

}

service.yml

parameters:
    acme_user.subscriber.fos_redirect.class: Acme\UserBundle\EventSubscriber\FOSUserRedirectSubscriber

services:
    acme_user.subscriber.fos_redirect:
        class: %acme_user.subscriber.fos_redirect.class%
        arguments:
            - @security.context
            - @router
        tags:
            - { name: kernel.event_subscriber }
qooplmao
  • 17,622
  • 2
  • 44
  • 69
  • Nice one, thank you. What do you think about my approach : Checking in the indexAction of the FOS-Controllers if the user is fully authenticated or not. If he is, i redirect him to the "account-area", if not, the template for e.g. login is rendered ?. Regards – nova.cp Nov 26 '14 at 16:58
  • It would work so it's not wrong, I just don't think it's the cleanest way of going about it. My main issues would be that you would have to extend/override each of the controllers individually, which would also mean having to use a child bundle for FOSUserBundle (if you already use one then it's not so much of an issue). It would also lead to a bit of repeated code as it would just be the same thing in each of the indexActions. Also with the approach that I gave you could also easily extend it to use interfaces with a couple of lines of code to cover @Alex's ideas. – qooplmao Nov 26 '14 at 20:57
  • Hi Qoop, i think using a child bundle when using FosUserBundle is "almost" necessary. But the point of rewriting and overriding each controller is - for me - the main aspect to use now your solution :) – nova.cp Nov 27 '14 at 08:53
  • Additional comment from my side: I really like your approach, because it blocks / checks the whole controller. Blocking only the index action wouldn't be enough. Then, someone couldn't e.g. enter the side, but could still reset his password if he already received his link, or activate a new account .. so blocking the whole controller is a very nice idea. Regards. – nova.cp Nov 27 '14 at 09:12
0

You can create a listener which will listen IntercativeLoginEvent. When it happens you can check which role has the authenticated user and redirect him wherever you want him to be redirected.

Look at these pages:

http://symfony.com/doc/current/components/security/authentication.html http://www.webtipblog.com/create-authentication-listener-symfony-2/

Hope, it helps.

Alex
  • 1,073
  • 9
  • 20
  • Hi, i think this is not what im looking for, because a listener would mean that the user can access the site and when he tries to submit, then i redirect him. I think i will check in the indexAction controller of e.g. RegistrationController if the user has role anonymously, and if not i redirect him to his profile. – nova.cp Nov 25 '14 at 11:17
  • You can implement interface (say, LimitedAccessInterface) which will implement each controller you to have limited access. And in the listener you can check if requested controller implements LimitedAccessInterface and user does not have appropriate permissions you will throw exception or return RedirectResponse or whatever you need. Of course you can check it right in your action, but what if you need ti implement it in several places? With interface you can just add interface to controller and that's it. You don't use FOSUserBundle, so I don't suggest you to look at next suggestion )) – Alex Nov 26 '14 at 04:34
  • You can look also at this page: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html – Alex Nov 26 '14 at 06:03