2017-09-22 36 views
4

在此之后Symfony3文档WSSE失败 “无法替换的参数,如果没有已配置但”

http://symfony.com/doc/current/security/custom_authentication_provider.html

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

我在任何地方都找不到这个错误。这使用文档的WSSE代码,并且失败。

此回购表明它没有https://github.com/jakenoble/wsse_test

我想要得到它与FOS用户捆绑最终工作。但我无法使用基本的Symfony3安装,因此FOS User Bundle目前无法正常工作。

说完周围挖了一下......

有一个在元素index_0Symfony\Component\DependencyInjection\ChildDefinition类的ARG在元素index_0的ARG对象具有的fos_user.user_provider.username_email的ID。

替换调用然后试图获得fos_user.user_provider.username_email的参数,但没有。然后发生错误。

任何想法?

回答

0

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

我看你不使用FOSUserBundle这使事情变得更加情结。我还没有创建公关。我想你是失踪custom user entity。 (请参阅我提供的链接来创建自己的实体 - 如果您无法使用描述和链接提供PR,但需要更长的时间才能创建自己的实体,那么我的PR将与这些行类似。你有

要采取的步骤:

  1. 通过src/AppBundle/Entity/User.php
  2. 创建自己的用户实体通过php bin/console doctrine:schema:update --force
  3. 创建数据库表配置Security加载您Entity - use AppBundle\Entity\User;
  4. 然后,你必须创建自己的用户。有关更多信息,请参阅password encoding
  5. 如果你想使用
  6. 的用户名登录或电子邮箱,你可以创建Custom Query to Load the User

这些步骤应该是足以让你创建自己的用户实体(可选)禁止交互用户,你没有使用FOSUserBundle。

+0

您是否拉回购回来并尝试修复?因为答案中没有任何内容会影响回购的基本实施。我有一个使用FOS User Bundle的版本,但它不起作用。它已经配置好了。 –

+0

@JakeN:请参阅我的编辑。我已经完全改变了答案。 – tukan

0

编辑:

好了,看了一些源代码,并在ChildDefinition:100你可以看到,该参数也被争论的$name索引。因此,在编译时,自动装配服务的参数必须与它们的命名索引(而不是编号索引)一起传递。

WsseFactory.php

->replaceArgument(0, new Reference($userProvider)); 

这样的说法应该由它的名称引用:

->replaceArgument('$userProvider', new Reference($userProvider)); 

此更改后,您将获得新的异常错误,它说,它不可能在WsseListener自动装配$authenticationManager通过它的界面提供服务。您只需在您的services.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'); 

3

这看起来像在这一刻提供商定义不具备自动装配Autowired论证准备,可能与其中“CompilerPass”被处理的顺序,现在你可以用这些小的调整解决这个问题:

改变这一行WsseFactory.php

->replaceArgument(0, new Reference($userProvider)) 

由:

->setArgument(0, new Reference($userProvider)) 

这个别名添加到services.yml完成新供应商的自动连接参数:

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

看来这个问题是因为我在services.yml配置新的自动布线的东西面前。

因此,简单地将它移动到汽车布线下方即可修复它。

+0

好吗?我试图将它移动到自动装配配置下,问题仍然存在 – yceruto

+0

为我修复了这个问题,我现在在使用它吗 –

3

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_secured定义。然后ResolveDefinitionTemplatesPass会发生,并会尝试更换定义的参数,提高Cannot replace arguments例外,你有:会出现

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); 
     } 
    } 

问题原因的传球将调用Definition::replaceArgumentindex_0。由于父母定义在位置0没有任何参数,前者services.xml也没有固定参数。 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::addArgumentDefinition::setArgument的电话,并会制定。只有一点区别: - setArgument(0, ...无法适用于其他一些场景; - 由于语义,我喜欢->setArgument('$userProvider'多于->replaceArgument('$userProvider'。没有什么可以替代!

希望详细说明问题的原因现在清楚了。

PS。还有其他几个有趣的方法来解决这个问题。

修复配置了一下:

AppBundle\Security\Authentication\Provider\WsseProvider: 
    arguments: 
     0: '' 
     $cachePool: '@cache.app' 
    public: false 

或一组Symfony\Component\Security\Core\User\UserProviderInterface别名,让自动装配为你做的休息。

$container 
     ->setDefinition($providerId, new ChildDefinition(WsseProvider::class)) 
    // ->replaceArgument(0, new Reference($userProvider)) 
    ; 
    $container 
     ->setAlias('Symfony\Component\Security\Core\User\UserProviderInterface',$userProvider) 
    ;