Symfony 4 - 安全性 - 从多个防火墙相互共享上下文

Posted

技术标签:

【中文标题】Symfony 4 - 安全性 - 从多个防火墙相互共享上下文【英文标题】:Symfony 4 - Security - Share context from multiple firewalls to one another 【发布时间】:2020-10-01 07:27:34 【问题描述】:

我认为我在 Symfony 安全组件方面达到了一些限制。这是我的问题:我有两个防火墙来管理两个用户类型(具有两个不同的实体)身份验证和对网站两个不同部分的访问。我有第三方来管理文件、上传……必须是私有的,并且两种用户类型都需要访问它。

所以我在security.yml中做了多个provider:

providers:
    # used to reload user from session & other features (e.g. switch_user)
    core_user_provider:
        entity:
            class: Akyos\CoreBundle\Entity\User
            property: email

    platform_user_provider:
        entity:
            class: App\Entity\Platform\UserPlatform
            property: email

    file_manager_provider:
        chain:
            providers: [core_user_provider, platform_user_provider]

还有多个防火墙

防火墙: 开发: 模式:^/(_(profiler|wdt)|css|images|js)/ 安全性:假

    core:
        pattern: ^/(app|admin)/
        context: shared
        provider: core_user_provider
        anonymous: lazy
        guard:
            authenticators:
                - Akyos\CoreBundle\Security\CoreBundleAuthenticator
        logout:
            path: app_logout
            target: 'home'
        remember_me:
            secret:   '%kernel.secret%'
            lifetime: 604800 # 1 week in seconds
            path:     /

    file_manager:
        pattern: ^/(file-manager)
        context: shared
        provider: file_manager_provider
        anonymous: lazy
        guard:
            authenticators:
                - App\Security\FileManagerAuthenticator
        logout:
            path: file_manager_logout
            target: 'home'
        remember_me:
            secret:   '%kernel.secret%'
            lifetime: 604800 # 1 week in seconds
            path:     /

    platform:
        pattern: ^/(platorm_login|plateforme)
        context: shared
        provider: platform_user_provider
        anonymous: lazy
        guard:
            authenticators:
                - App\Security\PlatformAuthenticator
        logout:
            path: platform_logout
            target: 'home'
        remember_me:
            secret:   '%kernel.secret%'
            lifetime: 604800 # 1 week in seconds
            path:     /

    main:
        anonymous: lazy

因此,Platform 用户无法访问 Core,Core 用户也无法访问 Platform。但是两个用户都需要访问文件管理器,而无需重新登录。我不能将 /file-manager url 放在核心或平台防火墙下,因为另一个不会授予访问权限。所以我需要第三个防火墙来管理文件管理器访问。它使用对核心用户和平台用户进行分组的链提供商。它也不起作用,因为如果核心用户通过核心防火墙进行身份验证,则它没有通过文件管理器的身份验证,因此它重定向到文件管理器登录页面。如果用户登录文件管理器部分,它可以访问它,但是当它返回核心部分时,它必须再次重新连接。

我尝试了几件事,但最接近的解决方案是在防火墙上使用上下文选项,因此当用户通过核心部分登录时,它可以访问文件管理器部分而无需重新登录,因为两个防火墙共享相同的上下文。这就是我想要的。但我也需要它用于平台防火墙!因此,我还为其添加了相同的上下文选项,并且它有效,两种用户类型都可以访问文件管理器而无需再次登录 :D 但是由于三个防火墙共享相同的上下文,核心用户可以访问平台,反之亦然,并且这打破了所有的分离逻辑.. :'(

我需要一种方法来告诉安全组件“文件管理器防火墙与核心防火墙具有相同的上下文,文件管理器防火墙与平台防火墙具有相同的上下文,但核心和平台防火墙不共享相同的上下文”。像这样的:

firewalls:

    core:
        context: core

    file_manager:
        context: [core,platform]

    platform:
        context: platform

    main:
        anonymous: lazy

我什么也没发现。也许它无法完成,也许我必须创建自定义提供程序或身份验证器来破解它。也许我可以在没有 Symfony 的情况下做到这一点,毕竟它只是 php,所以我可以让每个人都可以访问文件管理器部分(所以在主防火墙下)并添加一个侦听器来检查请求是否针对文件管理器,如果有以前登录的用户,则在会话中查找,检查用户是核心用户还是平台用户,如果不是则重定向...?在没有 Symfony 功能的情况下,如何在“主防火墙”页面(= 作为匿名身份验证)上找到会话中以前的 Core 或 Platform 用户?我还不够好,不知道如何实现这一目标。帮忙?

谢谢

【问题讨论】:

我认为你可以通过在 Symfony 中使用选民来实现这一点。您可以将其设置在路由上,而不是将其放在 security.yml 中。我已经为使用选民访问系统的不同部分的不同用户组实现了权限访问。 感谢您的回复。我添加了一个投票者来检查当前 $user 是否是 CoreUser 或 PlatformUser 的实例以授予访问权限,并在文件管理器控制器上添加了 @IsGranted("file-manager") 。我删除了 security.yml 中有关文件管理器部分的所有内容。这不是解决方案,因为我遇到了同样的错误:“访问此资源需要完全身份验证。”为什么 ? => 用户通过“核心”或“平台”防火墙进行身份验证,然后转到“主”防火墙下的/file-manager,并且上下文不共享,因此主防火墙不知道用户已登录。 【参考方案1】:

我终于让 3 个提供商和防火墙在它们之间共享了上下文。为了防止Core用户访问Platform,反之亦然,我添加了access_control:

-  path: ^/file-manager, roles: [ROLE_PLATFORM, ROLE_CORE] 
-  path: ^/core, roles: ROLE_CORE 
-  path: ^/plateforme, roles: ROLE_PLATFORM 

所以它以 403 拒绝访问错误结束。这不是我想要的行为,所以我还在核心和平台防火墙上添加了“access_denied_url”选项,以在良好的登录页面上重定向用户。由于上下文是共享的,用户已经登录,所以在登录模板上,我检查用户对象的实例,建议他在尝试访问这部分之前先断开连接。

% if instanceOf(app.user, 'App\\Entity\\PlatformUser') %
    You're already logged in Platform space, please <a href=" path('platform_logout') ">log out</a> before access Core space.
% else %
    You're already logged in as  app.user.username , <a href=" path('core_logout') ">log out</a> or <a href=" path('core_index') ">access core panel</a>.
% endif %

在不应该共享任何内容但访问文件管理器的部分之间共享上下文有点令人困惑,但没有用户可以访问其他部分,所以..这行得通。

【讨论】:

以上是关于Symfony 4 - 安全性 - 从多个防火墙相互共享上下文的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 4:如何在防火墙中为用户/管理员提供多个提供者?

symfony:在多个防火墙中模拟用户

Symfony2 安全不同的防火墙不能正确重定向到登录

Symfony2 中的多个动态防火墙和 CAS 服务器

从 symfony 4.4 中截取 login_check 路径

Symfony 安全返回 401 响应而不是重定向