Symfony impersonation - separate firewalls and sep

2019-04-10 16:33发布

问题:

I have a Symfony application with two firewalls, one for admins and one for normal users.

admin:
    provider: admin
    # etc

main_site:
    form_login:
        provider: fos_userbundle
        csrf_provider: form.csrf_provider

I'd like admin users to be able to impersonate normal users. How can I do this, given that they're using separate firewalls and separate user providers?

回答1:

There were several things I had to do to get this to work.

Context key: As described here, I had to give both firewalls the same context. Without this, admins were taken to the login page when trying to switch users.

Config on both firewalls: I had to add the basic switch_user configuration keys to both firewalls:

switch_user:
    role: ROLE_ADMIN

If I just put the config on the main_site firewall, admins got an access denied message when exiting impersonation and going to an admin page. (For example, the route /admin/dashboard?_switch_user=_exit would give a 403).

Provider key on the main_site's config:

main_site:
    switch_user:
        role: ROLE_ADMIN
        provider: fos_userbundle

Without this, I got the error "Switch User failed - user@example.com not found". Digging into the code, it turned out that the admin user provider was being used, and of course the normal users couldn't be found when using that provider.

(provider key for switch_user config discussed here.)

Alternatively, I could have added this as a provider key for the firewall itself:

main_site:
    switch_user:
        role: ROLE_ADMIN
    provider: fos_userbundle

You'll see from the config in my question that fos_userbundle was only specified as a provider for form_login, not for main_site as a whole, which is why it wasn't being used until I added it. Adding it in either place (impersonation config or whole firewall) would do the trick.

Here's the full set of relevant config:

admin:
    provider: admin
    # Have to put basic switch_user config on both firewalls
    switch_user:
        role: ROLE_ADMIN
    # Both the admin and main_site firewalls have the same context, to allow
    # cross-firewall impersonation
    # https://stackoverflow.com/a/17991481/328817
    context: boardworks

main_site:
    form_login:
        provider: fos_userbundle
        csrf_provider: form.csrf_provider
    switch_user:
        role: ROLE_ADMIN
        # Have to explicitly set the provider, otherwise the site will use the admin
        # user provider when looking up the users whom admins are trying to impersonate
        provider: fos_userbundle
    # Rather than adding the provider above, I could have added it here:
    #provider: fos_userbundle