国际化路由不适用于安全访问控制

Internationalized routing don't work fine with security access controls

我正在尝试使用 Internationalized routing

所以对于一条路线很多 URLs。

但有一条路线仍由其名称唯一标识。

这是一个很棒的功能,但文档没有说明如何处理安全组件。

事实上,我正在使用 url to make a basic secure of the app

但是由于每个 URL 在区域设置上可能不同,我发现让事情仍然有效的唯一方法是复制尽可能多的路径名称。

这是我现在的 security.yaml :

# ./config/packages/security.yaml @ line 27 -- 41
access_control:
        # Allow every user to visit index_no_locale page (Default page when no locale is selected).
        # This will redirect to login page with default locale.
        - { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow anonymous to visit login page.
        - { path: ^(/en/login|/fr/connexion|/de/verbindung), roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow anonymous to visit password_reset page.
        - { path: ^(/en/password/reset|/fr/mot-de-passe/reinitialisation|/de/passwort/zurücksetzen), roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow anonymous to visit email_send_password_forgot
        - { path: ^(/en/email/send/password/forgot|/fr/courriel/envoyer/mot-de-passe|/de/email/schreiben/passwort/vergessen), roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow only admin to visit admin url
        - { path: ^/admin, roles: IS_ADMIN}
        # Allow authenticated user ONLY to visit every other urls
        # Specific user right controls are managed inside controller
        - { path: ^/, roles: IS_AUTHENTICATED_FULLY}

正如我所说,这是可行的,但我必须为每条现有路线复制路径。

我让你看看路线以便更好地理解:

> php bin/console debug:router
  Name                             Method   Scheme   Host   Path      
-------------------------------- -------- -------- ------ --------------------
  password_reset.en                ANY      ANY      ANY    /{_locale}/password/reset/{user_id}/{token_value}           
  password_reset.fr                ANY      ANY      ANY    /{_locale}/mot-de-passe/reinitialisation/{user_id}/{token_value}
  password_reset.de                ANY      ANY      ANY    /{_locale}/passwort/zurücksetzen/{user_id}/{token_value}    
  login.en                         ANY      ANY      ANY    /{_locale}/login                                            
  login.fr                         ANY      ANY      ANY    /{_locale}/connexion                                        
  login.de                         ANY      ANY      ANY    /{_locale}/verbindung                                       
  logout                           ANY      ANY      ANY    /{_locale}/logout                                           
  index_no_locale                  ANY      ANY      ANY    /                 
...

我真的不喜欢这个,因为每次必须添加或修改 URL 时都会对 opeer 进行冗余修改。

主要问题是当用户未登录并访问需要 IS_AUTHENTICATED_FULLY 角色的 URL 时。

所以现在 'Voter' 表示访问被拒绝并将响应重定向到 login_path 定义为 security.yaml

问题来了。我无法定义 login_path 的正确路径,因为我无法猜测用户使用的语言环境是什么。所以我对此进行了硬编码:

# ./config/packages/security.yaml @ line 1 -- 21
security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        ...
    firewalls:
        dev:
            ...
        main:
            anonymous: true

            form_login:
                login_path: /en/login
                check_path: /en/login
                provider:   my_provider
            logout:
                path: /en/logout
            guard:
                ...

实际上注销也一样...

据此https://symfony.com/doc/current/security.html#logging-out

您可以让 security.firewalls.main.logout.path 引用路由名称。至于登录,您也可以参考路由名称,但推荐的方法是使用 guard authenticators 参见 https://symfony.com/doc/current/security/form_login.html.

编辑:

至于 access_control,当我查看 Symfony\Component\HttpFoundation\RequestMatcher 中的代码时,它不会查找路由名称。所以我看到了两个选项。

  1. 你找到了一种方法来创建你自己的 RequestMatcher 并让 Symfony 使用它,在我看来,这对于你需要的东西来说似乎过于复杂了。
  2. 为您现在正在做的 access_control 中的每个语言环境创建一个条目。为了更好的可读性,我通常会把每个条目放在自己的行上,而不是像你那样使用正则表达式 or,但我就是这样。