Search code examples
symfonysymfony6symfony-security

Form Authentication doesn't work with firewall's pattern property


I am using symfony 6, and facing some issues while having 2 authentication firewalls.

I need one to authenticate customer users, and another one for Dashboard users. To do so I setup 2 firewalls with different pattern. But it doesn't seem to work, as when I try to reach a secured page with the 'back_office' firewall, the profiler doesn't designate the right one, and submitting the authentication just reloads the form login.

Here is my security.yaml file :

security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
    Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
    users_in_memory: { memory: null }
    app_user_provider: 
        entity:
            class: App\Entity\Client
            property: email
    bo_user_provider:
        entity:
            class: App\Entity\BoUser
            property: email
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    back_office:
        pattern: ^/Dashboard
        lazy: true
        context: my_context
        provider: bo_user_provider
        form_login:
            login_path: bo_login
            check_path: bo_login
            enable_csrf: true
        logout:
            path: app_logout
    customer:
        lazy: true
        context: my_context
        pattern: ^/
        provider: app_user_provider
        form_login:
            login_path: app_login
            check_path: app_login
            enable_csrf: true
        logout:
            path: app_logout

When I request a secured route, I am redirected to the correct form login, but in the profiler I see that the firewall name is 'customer' : Symfony profiler - wrong firewall

After submitting the login form, the page reloads and I am not authenticated. No authentication errors are shown.

If I disable the customer firewall, I am still redirected to the correct form login, but no firewall is designated in the profiler : Symfony profiler - no firewall

If I comment the pattern property on the back_office firewall, then I am redirected to the correct form login, the profiler designates the right firewall, and I am able to authenticate correctly: Symfony profiler - right firewall

What am I doing wrong ?

Thanks in advance for your help !

Have a nice day

//UPDATE Here is the updated yaml file, as requested by ramsey_lewis

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        back_office:
            pattern: ^/Dashboard
            lazy: true
            provider: bo_user_provider
            form_login:
                login_path: bo_login
                check_path: bo_login
                enable_csrf: true
            logout:
                path: app_logout
        customer:
            # pattern: ^/Dashboard
            lazy: true
            provider: app_user_provider
            form_login:
                login_path: app_login
                check_path: app_login
                enable_csrf: true
            logout:
                path: app_logout

Solution

  • I found a workaround after all those days, I don't know if it's the best thing to do but it work.

    It's all related to the pattern property. I was using the same kind of pattern as you ^/login-admin and ^/login-user. The problem was the firewalls could only catch these 2 routes, but when I was redirected (after leaving the login form) the firewalls didnt know which one was called.

    I ended up creating a pattern only for my second login form, because all the user routes will be behind something like /user/profile, /user/item-123...

    And for my main login form (for admin firewall), I didn't set any pattern property. I just put the configuration for this specific firewall after the user firewall. With that, if the routes match something like /user/*, the user firewall it will be called, if it's something else not related to /user/*, the admin will be called. If the firewall can't catch anything, it will let other firewalls try to catch it

    firewalls:
        user:
            pattern: ^/(user\/.*)|/login-user|/logout-user
           ...
        admin:
            <--- no pattern property
            ...   
    

    hope this helps