2017-09-22 58 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) 
    ;