Is it possible to perform an automatic redirect to the some route (i.e. /) for the specific route /login
only for users that are AUTHENTICATED
? and
Another solution based on the @nifr answer. Overwriting only the renderLogin
function in your bundle controller. See also.
How to use Bundle Inheritance to Override parts of a Bundle
namespace MyProject\UserBundle\Controller;
//namespace FOS\UserBundle\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use \FOS\UserBundle\Controller\SecurityController as BaseController;
class SecurityController extends BaseController {
/**
* Renders the login template with the given parameters. Overwrite this function in
* an extended controller to provide additional data for the login template.
*
* @param array $data
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function renderLogin(array $data) {
if (true === $this->container->get('security.context')->isGranted('ROLE_USER')) {
return new RedirectResponse($this->container->get('router')- >generate('homeroute'));
}
$template = sprintf('FOSUserBundle:Security:login.html.%s', $this->container->getParameter('fos_user.template.engine'));
return $this->container->get('templating')->renderResponse($template, $data);
}
}
NB : I'm using Symfony 3.0.4@dev
This answer is based and the one that @nifr @mirk have provided and the comment of @Ronan.
To prevent the user access to the login page I override the SecurityController like this :
<?php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\SecurityController as BaseController;
class SecurityController extends BaseController
{
/**
* Renders the login template with the given parameters. Overwrite this function in
* an extended controller to provide additional data for the login template.
*
* @param array $data
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function renderLogin (array $data)
{
// This little if do the trick
if ($this->container->get('security.authorization_checker')->isGranted('ROLE_USER')) {
return new RedirectResponse($this->container->get ('router')->generate ('app_generation_page'));
}
$template = sprintf ('FOSUserBundle:Security:login.html.twig');
return $this->container->get ('templating')->renderResponse ($template, $data);
}
}
I've also added it to the RegistrationController to do the exact same thing.
Hope it will help some of you.
As you are using FOSUserBundle the rendering of the login form takes place in SecurityController::renderLogin().
The solution is bascially:
IS_AUTHENTICATD_ANONYMOUSLY
I assume you have already created a bundle extending FOSUserBundle which holds your User
Entity.
I assume this bundle is called YourUserBundle
and is located at src/Your/Bundle/UserBundle
.
Now copy (not cut) the SecurityController
vendor/friendsofsymfony/user-bundle/src/FOS/UserBundle/Controller/SecurityController.php
to (in order to override the one provided by FOSUserBundle)
src/Your/Bundle/UserBundle/Controller/SecurityController.php
add the use-statement for RedirectResponse
and edit the renderLogin()
method like this:
use Symfony\Component\HttpFoundation\RedirectResponse;
// ...
protected function renderLogin(array $data)
{
if (false === $this->container->get('security.context')->isGranted('IS_AUTHENTICATED_ANONYMOUSLY')) {
return new RedirectResponse('/', 403);
}
$template = sprintf('FOSUserBundle:Security:login.html.%s', $this->container->getParameter('fos_user.template.engine'));
return $this->container->get('templating')->renderResponse($template, $data);
}
Now instead of security.context
use security.authorization_checker
.
http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
It seems to me overriding the rendering of the login form is providing an answer in the wrong place. The rendering of the login form is not the one responsible for login. It's a result of the login request. It could have other usages elsewhere in the future and you'd be breaking functionality for those situations.
Overriding the login action seems better to me. That's the actual component responsible for handling the login request.
To do that, override the login action in the Security Controller. Say you have a MyUserBundle in your MyProject project which extends the FOSUserBundle.
<?php
namespace MyProject\MyUserBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\SecurityController as BaseSecurityController;
class SecurityController extends BaseSecurityController
{
/**
* Overriding login to add custom logic.
*/
public function loginAction(Request $request)
{
if( $this->container->get('security.context')->isGranted('IS_AUTHENTICATED_REMEMBERED') ){
// IS_AUTHENTICATED_FULLY also implies IS_AUTHENTICATED_REMEMBERED, but IS_AUTHENTICATED_ANONYMOUSLY doesn't
return new RedirectResponse($this->container->get('router')->generate('some_route_name_in_my_project', array()));
// of course you don't have to use the router to generate a route if you want to hard code a route
}
return parent::loginAction($request);
}
}
I'm using the routing and security to enable this.
#routing.yml
index:
path: /
defaults: { _controller: AppBundle:Base:index }
methods: [GET]
login:
path: /login
defaults: { _controller: AppBundle:Security:login }
methods: [GET]
If a user is logged in, he get redirected to the dashboard. If not, he will see the login route.
#security.yml
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/dashboard, role: ROLE_USER }
Hope this helps you. :)