Symfony 3,一个应用程序中有2个防火墙


Symfony 3, 2 firewalls in one app

我在symfony 3中的防火墙有问题。从 3 天开始,我一直在为此苦苦挣扎。我已经阅读了文档并根据它做了所有事情,但是应用程序没有按我预期工作。

目标:所有页面(登录页面除外)都需要登录用户。如果用户未登录,则应重定向到/login页面。就这样。

根据此页面:

  • http://symfony.com/doc/current/book/security.html
  • http://symfony.com/doc/current/cookbook/security/form_login_setup.html

我已经创建了具有登录操作和表单的控制器。 login_path和check_path使用相同的操作(根据文档)。可能是security.yml中的某些东西是错误的,因为它无法正常工作。 我的设置:

security:
providers:
    in_memory:
        memory:
            users:
                aaa:
                    password: aaa
                    roles: 'ROLE_ADMIN'
encoders:
    Symfony'Component'Security'Core'User'User: plaintext
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    login_firewall:
        pattern:    ^/login
        anonymous: ~
#       form_login:
#           login_path: /login
#           check_path: /login
    secured_area:
        pattern:    ^/
        form_login:
            login_path: /login
            check_path: /login
            default_target_path: homepage
        logout:
            path:   /logout
            target: /login
#    access_control:
#        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
#        - { path: ^/, roles: IS_AUTHENTICATED_FULLY }

我的登录操作:

<?php
/**
 * @Route("/login", name="login")
 */
public function loginAction(Request $request)
{
    $authenticationUtils = $this->get('security.authentication_utils');
    // get the login error if there is one
    $error = $authenticationUtils->getLastAuthenticationError();
    // last username entered by the user
    $lastUsername = $authenticationUtils->getLastUsername();
    return $this->render(
        'security/login.html.twig',
        array(
            // last username entered by the user
            'last_username' => $lastUsername,
            'error'         => $error,
        )
    );
}
?>

问题:

  1. 使用此配置,我无法登录。请求使用登录操作,但系统不想对我进行身份验证。
  2. 如果我在防火墙中取消注释form_login login_firewall身份验证,身份验证工作正常(我已登录),但我无法访问主页(尽管我已通过身份验证,但系统会将我重定向到登录页面。
  3. 我尝试使用access_control,但行为与 2 点相同。

请帮我。我确定这是一件简单的事情,但我是Symfony的新手,我没有看到它。

更新

感谢Tobias Xy,我更正了security.yml。工作版本:

security:
    providers:
        in_memory:
            memory:
                users:
                    smt:
                        password: smt
                        roles: 'ROLE_ADMIN'
    encoders:
        Symfony'Component'Security'Core'User'User: plaintext
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            form_login:
                login_path: /login
                check_path: /login
                default_target_path: /
            logout:
                path:   /logout
                target: /login
    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: IS_AUTHENTICATED_FULLY }

修复:

我建议:

  1. 完全删除login_firewall。
  2. 允许匿名用户进入您的secured_area(匿名:~)
  3. 取消注释access_control部分(内容看起来不错)

让我知道它是否有效。

替代修复:

(这可能有效,但我不是 100% 确定)。

  1. 将您的check_path更改为其他内容(例如/check_login)
  2. 为/check_login 创建一个空路由(类似于注销路由,如下所述:安全性 - 注销)
  3. (确保此新路径位于"secured_area"防火墙后面!

一些解释

您的问题可能可以通过此页面来解释:如何构建传统的登录表单。那里说:

如果使用多个防火墙,并且针对一个防火墙进行身份验证

,则不会自动针对任何其他防火墙进行身份验证。不同的防火墙就像不同的安全系统。

这解释了您的一些问题:如果您取消注释login_firewall中的form_login,您将仅对登录页面进行身份验证!一旦转到另一个页面,您将不再进行身份验证,因为它是不同的安全上下文。

我不是 100% 确定您的问题 1,但它可能会发生,因为您的"check_path"也在防火墙后面login_firewall而不是secured_area。由于您的login_firewall中没有form_login,因此无法识别提交的登录表单。