遵循此
http://symfony.com/doc/current/security/custom_authentication_provider.html
导致
service" security.authentication.provider.wsse.wsse_secured":如果没有配置,则不能替换参数。
我在任何地方都找不到有关此错误的任何信息。这使用了DOC的WSSE代码,并且失败了。
此仓库显示失败https://github.com/jakenoble/wsse_test
我想最终与FOS用户捆绑包一起使用。但是我无法与基本的Symfony3安装一起使用,因此FOS用户捆绑包目前不可能。
有点挖...
SymfonyComponentDependencyInjectionChildDefinition
上的元素 index_0
上有一个arg,在元素 index_0
处的arg对象具有 fos_user.user_provider.username_email
的ID。
替换呼叫然后尝试获取fos_user.user_provider.username_email
的参数,但没有。然后发生错误。
有什么想法?
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);
}
}
问题将出现,因为通行证将为index_0
调用Definition::replaceArgument
。由于父定义在以前的services.xml
中或固定固定的位置0中没有参数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, ...
不能在其他情况下使用; - 由于语义,我比->replaceArgument('$userProvider'
更喜欢->setArgument('$userProvider'
。尚无替换!
希望详细信息为什么现在出现问题。
ps。也很少有其他有趣的方法来克服这个问题。
修复配置:
AppBundleSecurityAuthenticationProviderWsseProvider:
arguments:
0: ''
$cachePool: '@cache.app'
public: false
或设置SymfonyComponentSecurityCoreUserUserProviderInterface
的别名,让自动射击为您完成。
$container
->setDefinition($providerId, new ChildDefinition(WsseProvider::class))
// ->replaceArgument(0, new Reference($userProvider))
;
$container
->setAlias('SymfonyComponentSecurityCoreUserUserProviderInterface',$userProvider)
;
此时,提供商定义还没有准备好自动参数,也许与现在处理" CompilerPass"的顺序有关您可以通过这些小调整来解决它:
在WsseFactory.php
中更改此行:
->replaceArgument(0, new Reference($userProvider))
:
->setArgument(0, new Reference($userProvider))
并将此别名添加到services.yml
中以完成新提供商的自动参数:
SymfonyComponentSecurityCoreAuthenticationAuthenticationManagerInterface: '@security.authentication.manager'
编辑:(由于注释而删除了先前的内容)
我看到您不使用fosuserbundle,这使事情变得更加糟糕。我还没有创建PR。
我认为您缺少自定义用户实体。(请参阅我为创建自己的实体提供的链接 - 如果您无法使用我的描述和我提供的PR的链接创建自己的实体,那么我的PR将与这些行相似,但这将需要更长的时间)。
您必须采取的步骤:
- 通过
src/AppBundle/Entity/User.php
创建自己的用户实体 - 通过
php bin/console doctrine:schema:update --force
创建DB表 - 配置
Security
加载您的Entity
-use AppBundleEntityUser;
- 然后,您必须创建自己的用户。这可能很棘手,请参阅密码编码更多。
- (可选)禁止交互式用户,如果您想使用 登录
- 用户名或电子邮件您可以创建
Custom Query to Load the User
这些步骤应该足以让您创建自己的用户实体,而您不必使用FosuserBundle。
编辑:
好吧,请阅读一些源代码,在ChildDefinition:100
中,您可以看到,参数也由参数的$name
索引。因此,必须在编译时通过其命名索引,而不是编号的索引。
WsseFactory.php
->replaceArgument(0, new Reference($userProvider));
因此,应以其名称引用参数:
->replaceArgument('$userProvider', new Reference($userProvider));
此更改后,您将获得新的异常错误,该错误表示无法通过其接口在WsseListener
中自动化$authenticationManager
。您可以通过在services.yml
中指定该接口的别名来修复它:
SymfonyComponentSecurityCoreAuthenticationAuthenticationManagerInterface: '@security.authentication.manager'
我想这个问题与新的autowire
功能有关,我将稍后尝试调查为什么它是这样的。
目前,您可以使用旧方法来定义服务:
services.yml:
app.security.wsse_provider:
class: AppBundleSecurityAuthenticationProviderWsseProvider
arguments:
- ''
- '@cache.app'
public: false
app.security.wsse_listener:
class: AppBundleSecurityFirewallWsseListener
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');
似乎问题是因为我的config in services.yml是在新的自动布线之前出现的。
因此,简单地将其移动在自动接线下方。