I am using the new login link method [1] in Symfony 5.2 for my customers. They should only use this authentication method. But I also use the login form authentication [2] for my admin users.

When an unauthenticated customer accesses a restricted path (in my case /app) he/she gets redirected to the form login instead of the login link form. This is also the case when the session has expired or if they access (unauthenticated) a bookmarked link within the restricted area.

How can I set the default authenticator for /app resp. /admin? I'd like to have something like this:

  • Customer area /app -> /login (Login Link Authenticator)
  • Admin area /admin -> /login-password (Login Form Authenticator)

My security.yaml looks like this:

security:
    encoders:
        App\Entity\User:
            algorithm: auto

    enable_authenticator_manager: true
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false    
        main:
            lazy: true
            provider: app_user_provider
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            login_link:
                check_route: login_check
                signature_properties: ['id']
                max_uses: 1
            logout:
                path: app_logout

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/app, roles: ROLE_USER }
        - { path: ^/, roles: PUBLIC_ACCESS }

[1] Login Link Method: https://symfony.com/doc/current/security/login_link.html
[2] LoginFormAuthenticator: https://symfony.com/doc/current/security/form_login_setup.html

1

There are 1 best solutions below

1
On

Ok, I figured a solution out myself. Please let me know, if there is a better solution!

I overwrite the start() method in the LoginFormAuthenticator class. There I store the $request obj in a private class prop because I can not overwrite the getLoginUrl() because of the definition in the AbstractFormLoginAuthenticator class. Then I add some logic in the getLoginUrl() method to check which area the user wants to access (/admin or /app) and redirect accordingly. That's it. Works like a charm. ;-)

// App\Security\LoginFormAuthenticator

    public const LOGIN_ROUTE                = 'admin_login';
    public const LOGIN_ROUTE_PASSWORDLESS   = 'app_login';

    ...

    private $request;

    ...

    /**
     * Override to control what happens when the user hits a secure page
     * but isn't logged in yet.
     *
     * @return RedirectResponse
     */
    public function start(Request $request, AuthenticationException $authException = null)
    {
        $this->request = $request;
        $url = $this->getLoginUrl();

        return new RedirectResponse($url);
    }

    ...

    protected function getLoginUrl()
    {
        // Check if user would like to access /app
        $path = $this->request->getPathInfo();
        
        if ('/app' === substr($path, 0, 4)) {
            return $this->urlGenerator->generate(self::LOGIN_ROUTE_PASSWORDLESS);
        }

        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }