security - Symfony2 : Injecting @security. 获取当前用户的上下文。如何避免 "ServiceCircularReferenceException"?注入(inject)整个容器?

标签 security symfony dependency-injection doctrine-orm

来自this post修复问题后,我遇到了另一个问题/安全问题/问题。

正如您在另一篇文章中可能看到的那样,我正在尝试在监听器中注入(inject)安全上下文,但如果我保持代码完整而不接触,则会收到此错误:

ServiceCircularReferenceException: Circular reference detected for service "doctrine.orm.default_entity_manager"

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

而不是注入(inject)[@security.context]我这样做了:

services:
    orderhascomment.listener:
        class: PL\OrderBundle\Listener\OrderHasCommentListener
        arguments: [@service_container]
        tags:
            - { name: doctrine.event_listener, event: prePersist, method: onPrePersist }

还有我的听众 OrderHasCommentListener.php如下:

namespace PL\OrderBundle\Listener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;

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

}

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

尝试在服务中转换 UserCallable

我正在尝试转换UserCallable按照说明在服务中 here并查看 DoctrineBehaviors orm-services.yml file并查看他们是如何做到的 BlameableListener但我无法让它工作,因为我收到此错误:

ContextErrorException: Catchable Fatal Error: Argument 1 passed to PL\OrderBundle\Listener\OrderHasCommentListener::__construct() must be callable, string given

这就是我的定义 app/config/config.yml 的样子:

services:
    orderhascomment.listener:
        class: PL\OrderBundle\Listener\OrderHasCommentListener
        arguments: 
            - user_callable
        tags:
            - { name: doctrine.event_listener, event: prePersist, method: onPrePersist }
    user_callable:
        class: PL\OrderBundle\Util\UserCallable
        arguments:
            - "@service_container"
        public:  false

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

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

出了什么问题?

最佳答案

将整个容器直接注入(inject)列表器可能是一个可行的解决方案......但我们可以做得更好:)

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

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

Knp\DoctrineBehaviors\ORM\Blameable\UserCallable

可以通过创建一个接口(interface)并在监听器中使用该接口(interface)进行类型提示来进一步改进此特定示例。如果您打算重复使用监听器,这可以更轻松地进行交换。

界面:

namespace Acme\Common;

interface UserCallableInterface
{
    /**
     * @return \Symfony\Component\Security\Core\User\UserInterface
     */
    public function getCurrentUser();
}
<小时/>
namespace Acme\Common;

use Symfony\Component\Security\Core\User\UserInterface;

interface TrackableInterface
{
    /**
     * @param UserInterface $user
     */
    public function setUser(UserInterface $user);
}

UserCallable:

namespace Acme\Util;

use Acme\Common\UserCallableInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

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 Acme\Common\UserCallableInterface;
use Acme\Common\TrackableInterface;
use Doctrine\Common\EventArgs;

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

关于security - Symfony2 : Injecting @security. 获取当前用户的上下文。如何避免 "ServiceCircularReferenceException"?注入(inject)整个容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22128402/

相关文章:

symfony - 如何在 Symfony 中注入(inject)验证器

c# - 在自己的 ServiceCollection 中获取 IConfiguration

javascript - 用于可配置依赖注入(inject)的 RequireJS 依赖覆盖

asp.net - 使用 WIF 安全 token 服务将用户的 asp.net session 限制为 1

symfony - 如何从服务中的 parameters.yml 中读取参数?

linux - 缓冲区溢出在 Linux 中失败?

mysql - DC2Type :array comment being added to field when doing a Doctrine migration diff

symfony - 注释 "@Route"从未被导入

asp.net-mvc - 渗透测试您的 MVC 应用程序

security - ngrok 使用起来安全吗还是会受到损害?