Locale switch in login of FOSUserBundle

2019-01-23 17:41发布

I'm trying to get locale switching to work in the login screen of my application. In order to do that I have links on my login page that point to site.com/ (the default locale) and site.com/en (the second locale I support). As soon as I've logged in, the switching works like a charm. However if I'm not yet authenticated the login always goes back to the default locale. My understanding was that if I use the named routes from FOSUserBundle then it's should be able to handle the locales automatically, but I can't get it to work.

My app/config/security.yml

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

    firewalls:
        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_provider: form.csrf_provider
                login_path: fos_user_security_login
                check_path: fos_user_security_check
            logout:       true
            anonymous:    true

    access_control:
        - { path: ^/_wdt, roles: IS_AUTHENTICATED_ANONYMOUSLY }         # allow wdt for debugging
        - { path: ^/_profiler/, role: IS_AUTHENTICATED_ANONYMOUSLY }    # allow profiler for debugging
        - { path: ^/bundles/, role: IS_AUTHENTICATED_ANONYMOUSLY }      # allow assets to be loaded anonymously

        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin, role: ROLE_ADMIN }
        - { path: ^/, role: ROLE_USER } 

My app/config/routing.yml

# FOS User bundle
fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"

fos_user_profile:
    resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
    prefix: /profile

#fos_user_register:
#    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
#    prefix: /register

fos_user_resetting:
    resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
    prefix: /resetting

fos_user_change_password:
    resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
    prefix: /profile

Any pointers much appreciated as I've been stuck with this for a couple of days now

4条回答
Root(大扎)
2楼-- · 2019-01-23 18:22

My solution: You have to redefine the fos_user routes for the be_simple_i18n type format. (I chose the yaml version):

In app/config/routing.yml

[...]
#register the path to the file with the be_simple_i18n type fos_user routes
fos_user:       
    resource: "config/routing/fos_user_i18n.yml"
    type: be_simple_i18n

my_yaml_i18n_routes:
    resource: "config/routing/i18n.yml"
    type: be_simple_i18n

In app/Resources/config/routing/fos_user_i18n.yml:

#you have to make entries for all the fos_user routes here!
#you can find them all in vendor/friendsofsymfony/user-bundle/Resources/routing
fos_user_security_login:
    locales:  { en: "/login", de: "/anmelden" }
    defaults: { _controller: FOSUserBundle:Security:login }
fos_user_security_check:
    locales:  { en: "/login_check", de: "/login_pruefung" }
    defaults: { _controller: FOSUserBundle:Security:check }
#...

In app/config/security.yml

firewalls:       
    [...]

    main:
        pattern: ^/
        form_login:
            provider: fos_userbundle
            login_path: fos_user_security_login
            check_path: fos_user_security_check
            csrf_provider: security.csrf.token_manager # Use form.csrf_provider instead for Symfony <2.4

        logout:
            path: fos_user_security_logout
            target: #where_no_one_has_gone_before
        [...]

access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/anmelden$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/registrieren, role: IS_AUTHENTICATED_ANONYMOUSLY }
    [...]
查看更多
Viruses.
3楼-- · 2019-01-23 18:22

I have been struggling a bit with this issue. I wanted to have the pure login (no URL in the session) to be redirected to the proper localized page. I could find the answer in the Symfony documentation:

# app/config/security.yml
security:
# ...
 firewalls:
    main:
        form_login:
            # ...
            default_target_path: index [ or your named route ]
查看更多
乱世女痞
4楼-- · 2019-01-23 18:30

The solution ended up being to prefix the locale to the route imports of FOSUserBundle:

# FOS User bundle
fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"
    prefix: /{_locale}

fos_user_profile:
    resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
    prefix: /{_locale}/profile

fos_user_register:
    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
    prefix: /{_locale}/register

fos_user_resetting:
    resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
    prefix: /{_locale}/resetting

fos_user_change_password:
    resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
    prefix: /{_locale}/profile

And also change the firewall to allow locales in the anonymous routes and configure the logout_path:

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

    firewalls:
        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_provider: form.csrf_provider
                login_path: fos_user_security_login
                check_path: fos_user_security_check
            logout:
                path:   fos_user_security_logout
            anonymous:    true

    access_control:
        - { path: ^/_wdt, roles: IS_AUTHENTICATED_ANONYMOUSLY }         # allow wdt for debugging
        - { path: ^/_profiler/, role: IS_AUTHENTICATED_ANONYMOUSLY }    # allow profiler for debugging
        - { path: ^/bundles/, role: IS_AUTHENTICATED_ANONYMOUSLY }      # allow assets to be loaded anonymously

        - { path: ^/[a-z]+/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/[a-z]+/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/[a-z]+/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin, role: ROLE_ADMIN }
        - { path: ^/, role: ROLE_USER } # this must be the last match, as url patterns are checked in the order they appear

Using the JMSI18nRoutingBundle would probably be better in the long term, but it did not work as a drop in solution when I tried it and the budget for this project did not allow me to start figuring out why not, so that will be left for a future update.

查看更多
太酷不给撩
5楼-- · 2019-01-23 18:35

I don't know how you're handling the locale detection/switch but with JMSI18nRoutingBundle you can do as below.

Add the required bundles to composer.json:

"require": {
    ...
    "jms/i18n-routing-bundle": "1.1.*",
    "jms/translation-bundle": "1.1.*",
    "friendsofsymfony/user-bundle": "1.3.*"
},

Configure the bundles:

jms_i18n_routing:
    default_locale: en
    locales: [en, fr, it, sp]
    strategy: prefix

Bootstrap the bundles:

$bundles = array(
    ...
    new JMS\I18nRoutingBundle\JMSI18nRoutingBundle(),
    new FOS\UserBundle\FOSUserBundle(),
);

Modify existing routes to prefix them with the desired locale:

access_control:
    # Routes are prefixed by ther user locale.
    - { path: ^/[^/]+/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/[^/]+/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/[^/]+/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/[^/]+/admin, role: ROLE_ADMIN }
    - { path: ^/[^/]+/, role: ROLE_USER }

Now it should work!

查看更多
登录 后发表回答