FOSUserBundle - How to redirect already logged-in

2019-01-26 15:43发布

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 }

5条回答
疯言疯语
2楼-- · 2019-01-26 16:24

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

查看更多
一夜七次
3楼-- · 2019-01-26 16:37

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.

查看更多
Luminary・发光体
4楼-- · 2019-01-26 16:38

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楼-- · 2019-01-26 16:43

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);
    }
}
查看更多
forever°为你锁心
6楼-- · 2019-01-26 16:45

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. :)

查看更多
登录 后发表回答