Sylius: [UserBundle] Authenticated user can still access the login page

Created on 16 Oct 2015  路  9Comments  路  Source: Sylius/Sylius

I know that this might be silly, but it's quite an annoying behaviour.

The scenario is:

  • I logged in the backend (/administration/login)
  • I'm redirected to the dashboard (/administration/dashboard)
  • If I try to access the backend login URL in the browser address bar, I'm not being redirected to the dashboard page (which I think it's the page I should be redirected considering I'm already logged in)
  • Instead of this, I can still access the login page.

I know that this is related to the firewall configuration. However, shouldn't a user be redirected to another page as the user is already logged in?

Checking this in the loginAction should do the work.


Potential Bug

Most helpful comment

Figured out a complete solution:

security.yml

#...
    firewalls:
#...
        shop:
            access_denied_handler: sylius.shop.access_denied_handler
#...
    access_control:
#...
        - { path: "%sylius.security.shop_regex%/login", allow_if: "is_anonymous()" }

        - { path: "%sylius.security.shop_regex%/register", allow_if: "is_anonymous()" }
#...
        - { path: "%sylius.security.shop_regex%/forgotten-password", allow_if: "is_anonymous()" }

services.yml

services:
#...
    sylius.shop.access_denied_handler:
            class: AppBundle\Security\AccessDeniedHandler
            arguments:
              - '@router'
              - '@security.authorization_checker'
              - '@session'
              - '@translator'

AccessDeniedHandler.php

<?php

namespace AppBundle\Security;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Translation\TranslatorInterface;

class AccessDeniedHandler implements AccessDeniedHandlerInterface {
    private $router;
    private $authChecker;
    private $session;
    private $translator;

    public function __construct(
        RouterInterface $router,
        AuthorizationCheckerInterface $authChecker,
        SessionInterface $session,
        TranslatorInterface $translator
    )
    {
        $this->router = $router;
        $this->authChecker = $authChecker;
        $this->session = $session;
        $this->translator = $translator;
    }

    public function handle(Request $request, AccessDeniedException $accessDeniedException)
    {
        if( $this->authChecker->isGranted('IS_AUTHENTICATED_FULLY') )
        {
            $this->session->getFlashBag()->add('info', $this->getFlashMessage('sylius.customer.already_logged_in'));
            return new RedirectResponse($this->router->generate('sylius_shop_account_dashboard'));
        }
    }

    private function getFlashMessage($key)
    {
        return $this->translator->trans($key, [], 'flashes');
    }
}

flashes.yml

sylius:
    customer:
        already_logged_in: 'You are already logged in'

I think that sorts it out.

All 9 comments

@herodrigues this happend with reset password related actions too

IMO, its more of symfony problem since im not aware of any quick&proper solution for it.

As a workaround you can restrict all these routes in your firewall config, create a 403 listener and handle redirect there(while setting flashmessage for example).

Definitely a bug we need to somehow handle. :) @okwinza solution seems like best what we have right now.

Is it really a bug? I don't think the page should be accessible, but it is harmless and doesn't break anything :)

@michalmarcinkowski I think it can be confusing for the user. I'd say it is not critical bug. :P

You can either create a 403 by adding:

- { path: ^/admin/login, role: IS_AUTHENTICATED_ANONYMOUSLY && !IS_AUTHENTICADED_FULLY }

But the best solution seems, to have a listener and redirect your to the dashboard. I'll create a PR for this right now.

As a clarification a user who is logged in can still access these pages:

  • /login
  • /register
  • /forgotten-password

I've tried looking through options for 403 handlers (authentication error handlers) but I can't seem to get a configuration that works. The config:
IS_AUTHENTICATED_ANONYMOUSLY && !IS_AUTHENTICADED_FULLY does not appear to work and non-logged in users are prevented access too and directed to the login page. I think this may need to be done within the controllers, which at least for the SecurityController, is a final class so cannot be overwritten.

Figured out a complete solution:

security.yml

#...
    firewalls:
#...
        shop:
            access_denied_handler: sylius.shop.access_denied_handler
#...
    access_control:
#...
        - { path: "%sylius.security.shop_regex%/login", allow_if: "is_anonymous()" }

        - { path: "%sylius.security.shop_regex%/register", allow_if: "is_anonymous()" }
#...
        - { path: "%sylius.security.shop_regex%/forgotten-password", allow_if: "is_anonymous()" }

services.yml

services:
#...
    sylius.shop.access_denied_handler:
            class: AppBundle\Security\AccessDeniedHandler
            arguments:
              - '@router'
              - '@security.authorization_checker'
              - '@session'
              - '@translator'

AccessDeniedHandler.php

<?php

namespace AppBundle\Security;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Translation\TranslatorInterface;

class AccessDeniedHandler implements AccessDeniedHandlerInterface {
    private $router;
    private $authChecker;
    private $session;
    private $translator;

    public function __construct(
        RouterInterface $router,
        AuthorizationCheckerInterface $authChecker,
        SessionInterface $session,
        TranslatorInterface $translator
    )
    {
        $this->router = $router;
        $this->authChecker = $authChecker;
        $this->session = $session;
        $this->translator = $translator;
    }

    public function handle(Request $request, AccessDeniedException $accessDeniedException)
    {
        if( $this->authChecker->isGranted('IS_AUTHENTICATED_FULLY') )
        {
            $this->session->getFlashBag()->add('info', $this->getFlashMessage('sylius.customer.already_logged_in'));
            return new RedirectResponse($this->router->generate('sylius_shop_account_dashboard'));
        }
    }

    private function getFlashMessage($key)
    {
        return $this->translator->trans($key, [], 'flashes');
    }
}

flashes.yml

sylius:
    customer:
        already_logged_in: 'You are already logged in'

I think that sorts it out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

loic425 picture loic425  路  3Comments

ping86 picture ping86  路  3Comments

inssein picture inssein  路  3Comments

Chrysweel picture Chrysweel  路  3Comments

javiereguiluz picture javiereguiluz  路  3Comments