我在向一些 Symfony 类添加自定义逻辑时遇到了问题。
切换用户监听器
我想添加一个检查,即用户不能切换到比初始用户拥有更多权限/角色的另一个用户。
第一次尝试
用密钥覆盖中的参数security_listeners.xml
:
security.authentication.switchuser_listener.class但是我在哪里可以覆盖它呢?
在 security.yml 中它不起作用:
security:
...
authentication:
switchuser_listener:
class: Symfony\Component\Security\Http\Firewall\SwitchUserListener
第二次尝试
覆盖 SwitchUserListner 服务 id 的服务:security.authentication.switchuser_listener
我在我的包的 service.xml 中创建了相同的服务,但我的类没有被使用/调用。
另一个想法是只覆盖类,但这仅适用于捆绑包,但 SwitchUserListener 不在 SecurityBundle 中,它在 symfony 组件目录中,在我看来,覆盖 SecurityBundle 是一个非常糟糕的主意
第三次尝试
现在我得到了解决方案:第一次我没有意识到调度程序调用了 SwitchUserListener 中的 SWTICH_USER 事件的侦听器:
$switchEvent = new SwitchUserEvent($request, $token->getUser());
$this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);
所以我只需要为这个事件类型创建一个带有特殊标签的服务:
<tag name="kernel.event_listener" event="security.switch_user" method="onSecuritySwitchUser" />
并在给定的方法中进行检查。
这似乎是比其他两个更好的解决方案。但是还有一个问题。在我的 SwitchUserEvent 监听器中,如果用户想要退出切换的用户,我需要忽略我的自定义检查。所以我需要检查请求的路径:ignore if path containts '?switch_user=_exit'
但是路径(URL参数)可以改变:
# app/config/security.yml
security:
firewalls:
main:
# ...
switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user }
但是在我的包中我无法读取这个参数,因为它不会被传递给service container
. 它将被传递给SwitchUserListner类的构造函数,并将作为私有属性保存在那里,永远不能从外部访问(没有反射)。(发生在这里:SecurityExtension.php
第 591 行)那该怎么办?定义参数两次反对 DRY。使用反射?
另一点是我编写订阅者类的每次事件都会被触发。那么什么是另一个/最好的解决方案呢?
我问这个问题是因为我会遇到一些类似的问题,我想添加或覆盖一些 symfony 实习生组件。
模板猜测器
我想修改TemplateGuesser
:对于一个特定的包,所有具有注释@Tempalte的模板都应该与控制器一起TestController#showAction
位于此路径:
Resources/views/customDir/Test/show.html.twig
所以猜测者应该被放置并将所有内容定位到一个额外的文件夹customDir而不是只使用views。当使用render
带有特定模板的函数时,猜测者应该忽略注释。
我创建了自己的 Guesser 并覆盖了服务 ID:sensio_framework_extra.view.guesser,与SwitchUserListener
这次相比,我的课程真正被调用而不是原来的guesser。为什么它在这里有效,但不适用于SwitchUserListener
?
这是一个很好的解决方案吗?我还尝试添加第二个侦听器,它调用 TemplateGuesser,它的服务sensio_framework_extra.view.listener与类Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener
但这没有用。