Symfony2:注入@security.context以获取当前用户。如何避免"ServiceCircularReferenceException"?注入整个容器?



来自这篇文章,在解决了问题之后,我又遇到了另一个问题/安全问题/问题。

正如你在另一篇文章中看到的那样,我试图在侦听器中注入安全上下文,但如果我不接触代码,就会出现以下错误:

ServiceCircularReferenceException:检测到的循环引用服务"条令.orm.default_entity_manager">

因此,通过阅读和研究,我找到了一个解决方案,但我不清楚它对我的应用程序来说是正确的还是安全的。这就是我所做的:

我没有注入[@security.context],而是这样做:

services:
orderhascomment.listener:
class: PLOrderBundleListenerOrderHasCommentListener
arguments: [@service_container]
tags:
- { name: doctrine.event_listener, event: prePersist, method: onPrePersist }

我的听众OrderHasCommentListener.php如下:

namespace PLOrderBundleListener;
use DoctrineORMEventLifecycleEventArgs;
use SymfonyComponentDependencyInjectionContainerInterface;
class OrderHasCommentListener {
protected $container;
public function __construct(ContainerInterface $container = null) {
$this->container = $container;
}
/**
*
* @param LifecycleEventArgs $args 
*/
public function onPrePersist(LifecycleEventArgs $args) {
$entity = $args->getEntity();
$user = $this->container->get('security.context')->getToken()->getUser();
$entity->setUser($user);
}
}

这样做对吗?或者存在另一个?我读到注入整个容器是个坏主意,因为我只需要安全上下文,那么解决方案是什么?(https://insight.sensiolabs.com/what-we-analyse)

尝试在服务中转换UserCallable

我正试图按照这里的说明转换服务中的UserCallable,查看DoctrineBehaviors orm-services.yml文件,并在BlameableListener上查看它们是如何实现的,但由于出现以下错误,我无法使其工作:

ContextErrorException:可捕获的致命错误:参数1传递给PL\OrderBundle\Listener\OrderHasCommentListener::__construct()必须为可调用,字符串给定

这就是我在app/config/config.yml:中的定义

services:
orderhascomment.listener:
class: PLOrderBundleListenerOrderHasCommentListener
arguments: 
- user_callable
tags:
- { name: doctrine.event_listener, event: prePersist, method: onPrePersist }
user_callable:
class: PLOrderBundleUtilUserCallable
arguments:
- "@service_container"
public:  false

这就是我在OrderHasCommentListener.php文件中传递给__construct()函数的方式:

/**
* @param UserCallableInterface $user_callable 
* */
public function __construct(callable $user_callable = null) {
$this->userCallable = $user_callable;
}

怎么了?

将整个容器直接注入lister可能是一个有效的解决方案。。。但我们可以做得更好:)

注入一个返回当前用户的UserCallable

通过这种方式,您可以更清楚地表达dependency的真正目的,而不会在侦听器和容器(-interface)之间引入硬依赖关系。一个例子是。。。

KnpDoctrineBehaviorsORMBlameableUserCallable

这个特殊的例子可以通过创建一个接口并在监听器中使用它来进行类型提示来进一步改进。如果您计划重用侦听器,这将允许更容易的交换。

接口:

namespace AcmeCommon;
interface UserCallableInterface
{
/**
* @return SymfonyComponentSecurityCoreUserUserInterface
*/
public function getCurrentUser();
}
namespace AcmeCommon;
use SymfonyComponentSecurityCoreUserUserInterface;
interface TrackableInterface
{
/**
* @param UserInterface $user
*/
public function setUser(UserInterface $user);
}

可调用用户:

namespace AcmeUtil;
use AcmeCommonUserCallableInterface;
use SymfonyComponentDependencyInjectionContainerInterface;
class UserCallable implements UserCallableInterface
{
/** @var ContainerInterface **/
protected $container;
/** 
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* @{inheritdoc}
*/
public function getCurrentUser()
{
return $this->container->get('security.context')->getToken()->getUser() ?: false;
}

监听器:

use AcmeCommonUserCallableInterface;
use AcmeCommonTrackableInterface;
use DoctrineCommonEventArgs;
class Listener
{
/** @var UserCallableInterface **/
protected $userCallable;
/** 
* @param UserCallableInterface $user_callable 
**/    
public function __construct(UserCallableInterface $user_callable)
{
$this->userCallable = $user_callable;
}
/** 
* @param EventArgs $args 
**/
public function onPrePersist(EventArgs $args)
{
$entity = $args->getEntity();
if ( !($entity instanceof TrackableInterface) ) {
return;
}
if ( !($user = $this->userCallable->getCurrentUser())) {
return;
}
$entity->setUser($user);
}      
}

相关内容

  • 没有找到相关文章

最新更新