Symfony 5.2.11:创建自定义访问决策管理器时出现问题

Symfony 5.2.11: Problem with creating Custom Access Decision Manager

我正在尝试通过在 Symfony 5.2 上实现 AccessDecisionManagerInterface 来创建自定义访问决策管理器。

Symfony 识别决策管理器并将其实例化,但它不会将 Voters 数组传递给决策管理器。所以它不能收集选票,但默认的决策管理器工作正常。我遵循了 Symfony 网站上提供的信息。我也已将决策管理器文件复制到我的 App\Security 并只是更改了 class+ 文件名,但它没有用。将自定义决策管理器添加到 service.yml 也没有帮助。

有没有人遇到过同样的问题?有机会修复它吗?

更新#1

参考问题https://github.com/symfony/symfony/issues/41123

我遇到了不同症状的这个问题!

虽然我知道该服务是自动注册的,但我在 service.yml:

中这样做了
    App\Security\SpecialAccessDecisionManager:
        class: App\Security\SpecialAccessDecisionManager  
        autowire: false
        autoconfigure: false
        public: false

然后我将决策管理器添加到 security.yml:

security:
    access_decision_manager:
        service: App\Security\SpecialAccessDecisionManager

如下所示,参数尚未传递给决策管理器:

[root@dev7 rouzonline.test]# bin/console debug:container debug.security.access.decision_manager.inner --show-arguments                            

 // This service is a private alias for the service                                                                     
 // App\Security\SpecialAccessDecisionManager                                                                           

Information for Service "App\Security\SpecialAccessDecisionManager"
===================================================================

 Description of SpecialAccessDecisionManager

 ---------------- ------------------------------------------- 
  Option           Value                                      
 ---------------- ------------------------------------------- 
  Service ID       App\Security\SpecialAccessDecisionManager  
  Class            App\Security\SpecialAccessDecisionManager  
  Tags             -                                          
  Public           no                                         
  Synthetic        no                                         
  Lazy             no                                         
  Shared           yes                                        
  Abstract         no                                         
  Autowired        no                                         
  Autoconfigured   no                                         
 ---------------- ------------------------------------------- 


 ! [NOTE] The "debug.security.access.decision_manager.inner" service or alias has been removed or inlined when the      
 !        container was compiled.                                                                                       

[root@dev7 rouzonline.test]#

当我使用默认 AccessDecisionManager 时,投票者通过了。我需要实施特殊授权,所以我需要创建自己的决策管理器。顺便说一下,我的决策管理器实现了 AccessDecisionManagerInterface

我也检查了 \SecurityBundle\DependencyInjection\Compiler\AddSecurityVotersPass->process() ,当我的决策管理器设置时它没有被调用。

更新#2 为了测试,我临时改名为 default AccessDecisionManager.php 并放置了我的 decision manager,它出人意料地起作用了。但这不是解决方案。仍在寻找正确的解决方案。

谢谢大家的回复和帮助,我明白了

解决方法

当 Symfony 编译代码时,它(不知何故)有自己的服务定义,所以它不会混淆。我将代码跟踪到已编译的缓存中,发现它无法确定我的 ADM 的服务定义。所以我改变了我的 service.yml 并定义参数如下:

    security.access.decision_manager:
        class: App\Security\SpecialAccessDecisionManager  
        arguments:
            - []
            - 'affirmative'
            - false
            - true

vendor/symfony/security-bundle/DependencyInjection/Compiler/AddSecurityVotersPass.php里面我发现有参数替换,它通过数字枚举服务参数,这就是我添加未命名服务参数的原因。

        $container->getDefinition('security.access.decision_manager')
            ->replaceArgument(0, new IteratorArgument($voterServices));
    }

跟踪显示到目前为止,Symfony 正确收集了所有选民,因此不需要手动管理依赖项。

通过使用这个 service.yml,我不需要在 security.yml 中定义 access_decision_manager

发现问题后,我尝试使用access_decision_manager但它导致了同样的错误,意味着它没有收到选民名单。然后我决定停止解决这个问题,因为它现在对我有用。

结论

我知道 AccessDecisionManager 在某种程度上是一个很深的 Symfony 概念,很少用于普通项目,但是:

  1. 文档没有充分涵盖这部分内容
  2. 当开发人员实现接口并将其注入 Symfony 时,它应该被视为与本机代码完全相同,或者提供足够的描述性日志或详细信息以显示违规行为
  3. 我解决问题的方法不标准,以后可能需要修改
  4. Symfony 在处理来自 security.yml
  5. access_decision_manager 时出现异常

可能 Symfony 的这一部分需要复习。