Symfony3文件WSSE失败“;如果尚未配置任何参数,则无法替换参数";

Symfony3文件WSSE失败“;如果尚未配置任何参数,则无法替换参数";,symfony,wsse,Symfony,Wsse,此后 导致 服务“security.authentication.provider.wsse.wsse_securied”:如果尚未配置任何参数,则无法替换参数 我在任何地方都找不到关于这个错误的任何信息。这将使用文档的WSSE代码,但失败 这一回购协议表明它失败了 我想让它最终与FOS用户包一起工作。但我无法让它与基本的Symfony3安装一起工作,所以FOS用户包目前是不可能的 在附近挖了一点 类Symfony\Component\DependencyInjection\ChildDefi

此后

导致

服务“security.authentication.provider.wsse.wsse_securied”:如果尚未配置任何参数,则无法替换参数

我在任何地方都找不到关于这个错误的任何信息。这将使用文档的WSSE代码,但失败

这一回购协议表明它失败了

我想让它最终与FOS用户包一起工作。但我无法让它与基本的Symfony3安装一起工作,所以FOS用户包目前是不可能的

在附近挖了一点

Symfony\Component\DependencyInjection\ChildDefinition
上有一个arg at元素
index\u 0
的arg at元素对象的id为
fos\u user.user\u provider.username\u email

然后replace调用尝试获取fos\u user.user\u provider.username\u email的参数,但没有参数。然后发生错误

有什么想法吗?

编辑:(由于评论,删除了以前的内容)

我知道你没有使用FOSUserBundle使事情变得更复杂。我还没有创建公关

我想你失踪了。(请参阅我为创建您自己的实体提供的链接-如果您无法使用我的描述和我将提供的PR链接创建您自己的实体,我的PR将类似于这些行,但这将需要更长的时间)

您必须采取的步骤:

  • 通过
    src/AppBundle/entity/User.php创建您自己的用户实体
  • 通过
    php bin/console原则创建数据库表:schema:update--force
  • 配置
    安全性
    以加载您的
    实体
    -
    使用AppBundle\Entity\User
  • 然后,您必须创建自己的用户。这可能很棘手,请参阅了解更多信息
  • (可选)如果要使用登录,请禁止交互式用户
  • 用户名或电子邮件您可以创建
    自定义查询以加载用户
  • 这些步骤应该足以让您创建自己的用户实体,并且您不必使用FOSUserBundle。

    编辑:

    好的,阅读一些源代码,在中您可以看到,参数也由参数的
    $name
    索引。因此,在编译时,自动连线服务的参数必须与其命名索引(而不是编号索引)一起传递

    WsseFactory.php

    ->replaceArgument(0, new Reference($userProvider));
    
    所以参数应该由它的名称引用:

    ->replaceArgument('$userProvider', new Reference($userProvider));
    
    此更改后,您将获得新的异常错误,这表示无法通过其接口在
    WsseListener
    服务中自动连线
    $authenticationManager
    。您只需在
    服务中为该接口指定别名即可解决此问题。yml

    Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface: '@security.authentication.manager'
    

    我猜这个问题与新的
    autowire
    功能有关,稍后我将尝试研究它为什么会这样

    现在,您可以使用旧方法定义服务:

    services.yml:

    app.security.wsse_provider:
        class: AppBundle\Security\Authentication\Provider\WsseProvider
            arguments:
                - ''
                - '@cache.app'
            public: false
    
    app.security.wsse_listener:
        class: AppBundle\Security\Firewall\WsseListener
        arguments: ['@security.token_storage', '@security.authentication.manager']
        public: false
    
    在WsseFactory.php中,显示以下行:

    new ChildDefinition(WsseFactory::class);
    new ChildDefinition(WsseListener::class);
    
    翻译成:

    new ChildDefinition('app.security.wsse_provider');
    new ChildDefinition('app.security.wsse_listener');
    

    此时看起来,提供程序定义没有准备好自动连接参数,可能与“CompilerPass”的处理顺序有关,现在您可以通过以下小调整来解决它:

    WsseFactory.php
    中更改此行:

    ->replaceArgument(0, new Reference($userProvider))
    
    作者:

    并将此别名添加到
    services.yml
    以完成新提供者的自动连接参数:

    Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface: '@security.authentication.manager'
    

    问题似乎是因为我在services.yml中的配置出现在新的自动布线之前


    因此,只需将其移动到自动布线下方即可修复它。

    TL;DR将您的服务定义移动到
    services.yml中的自动加载定义下方,并将
    WsseFactory
    代码更改为

        $container
            ->setDefinition($providerId, new ChildDefinition(WsseProvider::class))
            ->setArgument('$userProvider', new Reference($userProvider))
        ;
    
    完整解释。 提供的代码中的第一个错误是服务定义在自动加载行之前。自动加载将覆盖前面的定义,并将导致AuthenticationManagerInterface失败。移动下面的定义将解决此问题。另一种解决问题的方法是使用@yceruto和@gintko指出的别名

    但是,尽管你的答案是正确的,但只有这一步不会使代码起作用。你可能没有注意到如何改变其他东西使其工作

    第二个问题是
    replaceArgument
    的失败,它与Symfony正确假设的容器编译顺序有关。顺序在
    PassConfig
    类中定义:

    $this->optimizationPasses = array(array(
            new ExtensionCompilerPass(),
            new ResolveDefinitionTemplatesPass(),
            ...
            $autowirePass = new AutowirePass(false),
            ...
        ));
    
    我省略了不相关的通行证。首先生成由
    WsseFactory
    创建的
    security.authentication.provider.wsse.wsse\u securied
    定义。然后将发生
    ResolveDefinitionTemplatesPass
    ,并将尝试替换定义的参数,并引发您遇到的
    无法替换参数
    异常:

        foreach ($definition->getArguments() as $k => $v) {
            if (is_numeric($k)) {
                $def->addArgument($v);
            } elseif (0 === strpos($k, 'index_')) {
                $def->replaceArgument((int) substr($k, strlen('index_')), $v);
            } else {
                $def->setArgument($k, $v);
            }
        }
    
    该问题将出现,因为该过程将调用
    索引0
    定义::replaceArgument
    。因为父定义在前一个
    services.xml
    或固定的位置0处都没有参数
    AutowirePass
    尚未执行,自动生成的定义没有参数,手动定义只有命名的
    $cachePool
    参数

    因此,要解决此问题,您可以使用:

    ->setArgument(0, new Reference($userProvider)); //proposed by @yceruto
    ->replaceArgument('$userProvider', new Reference($userProvider)); //proposed by @gintko
    ->setArgument('$userProvider', new Reference($userProvider)); // by me
    
    所有这些都需要调用
    Definition::addArgument
    Definition::setArgument
    ,并将得到解决。只有一点区别: -
    setArgument(0,…
    无法用于其他一些场景; -我喜欢
    ->setArgument('$userProvider'
    )而不是
    ->replaceArgument('$userProvider'
    ),这是因为语义原因。还没有什么可以替换的

    希望问题出现的细节现在清楚了

    PS.还有一些其他有趣的方式可以让你轻松一下
    ->setArgument(0, new Reference($userProvider)); //proposed by @yceruto
    ->replaceArgument('$userProvider', new Reference($userProvider)); //proposed by @gintko
    ->setArgument('$userProvider', new Reference($userProvider)); // by me
    
    AppBundle\Security\Authentication\Provider\WsseProvider:
        arguments:
            0: ''
            $cachePool: '@cache.app'
        public: false
    
        $container
            ->setDefinition($providerId, new ChildDefinition(WsseProvider::class))
        //    ->replaceArgument(0, new Reference($userProvider))
        ;
        $container
            ->setAlias('Symfony\Component\Security\Core\User\UserProviderInterface',$userProvider)
        ;