问题
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 How?
I'm using FOSUserBundle.
This is my security configuration:
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /accedi
check_path: /login_check
default_target_path: /
oauth:
resource_owners:
facebook: "/login/check-facebook"
google: "/login/check-google"
login_path: /accedi
failure_path: /accedi
default_target_path: /
oauth_user_provider:
service: my_user_provider
logout:
path: /logout
target: /
invalidate_session: false
anonymous: ~
login:
pattern: ^/login$
security: false
remember_me:
key: "%secret%"
lifetime: 31536000 # 365 days in seconds
path: /
domain: ~
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: fos_userbundle
check_path: _security_check
login_path: _demo_login
anonymous: true
oauth_token:
pattern: ^/oauth/v2/token
security: false
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/accedi$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/registrati, role: IS_AUTHENTICATED_ANONYMOUSLY }
回答1:
As you are using FOSUserBundle the rendering of the login form takes place in SecurityController::renderLogin().
The solution is bascially:
- overriding the SecurityController
- adding a check for the role
IS_AUTHENTICATD_ANONYMOUSLY - redirecting the user to another page if the role was not found
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);
}
Update
Now instead of security.context use security.authorization_checker.
http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
回答2:
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);
}
}
回答3:
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.
回答4:
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);
}
}
回答5:
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. :)
来源:https://stackoverflow.com/questions/20190289/fosuserbundle-how-to-redirect-already-logged-in-users-when-trying-to-access-th