【问题标题】:Symfony2: Inject current user in ServiceSymfony2:在服务中注入当前用户
【发布时间】:2012-04-16 22:49:55
【问题描述】:

我正在尝试将当前登录的用户注入到服务中。我的目标是扩展一些树枝功能以根据用户偏好输出它。在此示例中,我想使用用户特定的时区输出任何日期函数。

似乎没有任何方法可以将当前用户注入服务,这对我来说似乎很奇怪。注入安全上下文时,即使用户登录也没有令牌

我正在使用 FOS 用户包。

services:
    ...
    twigdate.listener.request:
        class: App\AppBundle\Services\TwigDateRequestListener
        arguments: [@twig, @security.context]
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }


<?php

namespace App\AppBundle\Services;

use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;

class TwigDateRequestListener
{
    protected $twig;

    function __construct(\Twig_Environment $twig, SecurityContext $context) {

        $this->twig = $twig;
        //$this->user = $context->get...;

        var_dump($context); die;
    }

    public function onKernelRequest(GetResponseEvent $event) {
       // $this->twig->getExtension('core')->setDateFormat($user->getProfile()->getFormat());
       // $this->twig->getExtension('core')->setTimeZone($user->getProfile()->getTimezone());
    }
}

output:

object(Symfony\Component\Security\Core\SecurityContext)[325]
  private 'token' => null
  private 'accessDecisionManager' => 
    object(Symfony\Component\Security\Core\Authorization\AccessDecisionManager)[150]
      private 'voters' => 
        array
          0 => 
            object(Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter)[151]
              ...
          1 => 
            object(Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter)[153]
              ...
          2 => 
            object(Symfony\Component\Security\Acl\Voter\AclVoter)[155]
              ...
      private 'strategy' => string 'decideAffirmative' (length=17)
      private 'allowIfAllAbstainDecisions' => boolean false
      private 'allowIfEqualGrantedDeniedDecisions' => boolean true
  private 'authenticationManager' => 
    object(Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager)[324]
      private 'providers' => 
        array
          0 => 
            object(Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider)[323]
              ...
          1 => 
            object(Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider)[149]
              ...
      private 'eraseCredentials' => boolean true
  private 'alwaysAuthenticate' => boolean false

我错过了什么吗?

【问题讨论】:

    标签: php dependency-injection symfony fosuserbundle


    【解决方案1】:

    我认为自从 2.6.x+ 新的安全组件改进以来,这个问题值得更新答案。

    use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
    
    class UserDateExtension extends \Twig_Extension
    {
        /**
         * @var TokenStorage
         */
        protected $tokenStorage;
    
    
        /**
         * @param \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage    $tokenStorage
         */
        public function __construct(TokenStorage $tokenStorage)
        {
            $this->tokenStorage = $tokenStorage;
        }
    
        public function getUser()
        {
            return $this->tokenStorage->getToken()->getUser();
        }
    
        public function getFilters()
        {
            return array(
                'user_date' => new \Twig_Filter_Method($this, "formatUserDate"),
            );
        }
    
        public function formatUserDate($date, $format)
        {
            $user = $this->getUser();
            // do stuff
        }
    }
    

    Services.yml

    twig.date_extension:
        class: Acme\Twig\SpecialDateExtension
        tags:
            - { name: twig.extension }
        arguments:
            - "@security.token_storage"
    

    【讨论】:

      【解决方案2】:

      我会为此使用树枝扩展:

      class UserDateExtension extends \Twig_Extension
      {
          private $context;
      
          public function __construct(SecurityContext $context)
          {
              $this->context = $context;
          }
      
          public function getUser()
          {
              return $this->context->getToken()->getUser();
          }
      
          public function getFilters()
          {
              return array(
                  'user_date' => new \Twig_Filter_Method($this, "formatUserDate"),
              );
          }
      
          public function formatUserDate($date, $format)
          {
              $user = $this->getUser();
              // do stuff
          }
      

      现在在services.xml

          <service id="user_date_twig_extension" class="%user_date_twig_extension.class%">
              <tag name="twig.extension" />
              <argument type="service" id="security.context" />
          </service>
      

      然后你可以在树枝上做:

      {{ date | user_date('d/m/Y') }}
      

      【讨论】:

      • 感谢这完美的工作。我仍然不明白为什么我的第一个示例没有返回用户对象,但我让它工作了,我认为 Twig Extension 实际上是一种更清洁的方法。感谢您的快速回复
      • 你正在监听kernel.request 事件。在所有 kernel.request 侦听器被调度之后,通过身份验证设置上下文令牌或从会话中读取令牌完成。如果您已经收听了kernel.response 事件,那么您将获得所需的令牌。也很抱歉误读您的问题。这对我来说是糟糕的一天:)。
      • 这是有道理的。感谢您的解释。你每天都会学到一些东西。
      • SecurityContext (security.context) 自 2.6 起已弃用。改用 security.token_storage
      • 除了@nutrija 的评论,请看:symfony.com/blog/…
      【解决方案3】:

      services.yml

      my_service:
          class: ...
          arguments:
              - "@=service('security.token_storage').getToken().getUser()"
      

      服务.php

      protected $currentUser;
      
      public function __construct($user)
      {
          $this->currentUser = $user;
      }
      

      http://symfony.com/doc/current/book/service_container.html#using-the-expression-language

      【讨论】:

      • 这是 2016 年 symfony 2.6 及更高版本的最佳答案
      • 它可以在安全防火墙之外工作吗?我的意思是,它返回“null”还是抛出异常,因为 getToken() 返回 null 并且 ->getUser() 不能应用于 null 对象?
      • 适用于 Symfony 3.2
      • 我相信这是在没有用户时抛出错误。
      【解决方案4】:

      用户不适合成为服务。

      • 首先它是一个模型而不是一个服务
      • 其次是服务security.context,您可以从中获取用户。

      在树枝模板中,您可以使用 app.user。请参阅 symfony 文档 global-template-variables。 如果您想根据用户权限显示某些内容,您可以执行 {{ is_granted('ROLE_USER') }}。

      【讨论】:

        【解决方案5】:

        来自 Symfony 2.6。

        你需要使用@security.token_storage

        use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
        
        class UserDateExtension extends \Twig_Extension
        {
        /**
         * @var TokenStorageInterface
         */
        protected $tokenStorage;
        
        
        /**
         * @param $tokenStorage TokenStorage
         */
        public function __construct(TokenStorage $tokenStorage)
        {
            $this->tokenStorage = $tokenStorage;
        }
        
        public function getUser()
        {
            return $this->tokenStorage->getToken()->getUser();
        }
        
        public function getFilters()
        {
            return array(
                'user_date' => new \Twig_Filter_Method($this, "formatUserDate"),
            );
        }
        
        public function formatUserDate($date, $format)
        {
            $user = $this->getUser();
            // do stuff
        }
        

        }

        和 Services.yml

        twig.date_extension:
            class: Acme\Twig\SpecialDateExtension
            tags:
                - { name: twig.extension }
            arguments: ["@security.token_storage"]
        

        参考:http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements

        【讨论】:

          【解决方案6】:

          我建议绑定一个不同的事件,如果你使用 kernel.controller 事件,你会有一个令牌,没有问题。令牌在kernel.request 中不可用,因为Symfony 2.3

          我在名为 Symfony 2.6+ User Timezones 的博客上写了一篇关于如何在 Twig 中为 Symfony 2.3+2.6+ 实现用户时区的指南。

          这比使用 Twig 扩展要好得多,因为您可以在 Twig 中使用标准日期格式化功能,并提供单独的后端 UTC 日期、默认 Twig 日期时区和用户定义的 Twig 日期时区。

          这是最重要的摘录:

          src/AppBundle/EventListener/TwigSubscriber.php

          <?php
          
          namespace AppBundle\EventListener;
          
          use AppBundle\Entity\User;
          use Symfony\Component\EventDispatcher\EventSubscriberInterface;
          use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
          use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
          
          class TwigSubscriber implements EventSubscriberInterface
          {
              protected $twig;
              protected $tokenStorage;
          
              function __construct(\Twig_Environment $twig, TokenStorageInterface $tokenStorage)
              {
                  $this->twig = $twig;
                  $this->tokenStorage = $tokenStorage;
              }
          
              public static function getSubscribedEvents()
              {
                  return [
                      'kernel.controller' => 'onKernelController'
                  ];
              }
          
              public function onKernelController(FilterControllerEvent $event)
              {
                  $token = $this->tokenStorage->getToken();
          
                  if ($token !== null) {
                      $user = $token->getUser();
          
                      if ($user instanceof User) {
                          $timezone = $user->getTimezone();
                          if ($timezone !== null) {
                              $this->twig->getExtension('core')->setTimezone($timezone);
                          }
                      }
                  }
              }
          }
          

          现在您可以正常使用 twig,它会使用您的用户偏好(如果可用)。

          【讨论】:

            【解决方案7】:

            您可以尝试注入@service_container 并执行$this-&gt;container-&gt;get('security.context')-&gt;getToken()-&gt;getUser();

            【讨论】:

            • 在大多数情况下注入整个容器是个坏主意。相反,您应该明确地注入您需要的每项服务。
            • Twig 扩展是此规则的例外之一。
            • @elnur,对不起,我错了。似乎帮助服务FacebookExtension 使用有templating.helper 标签。这可能与扩展名冲突。你是对的,注入@service_container 是个坏主意。
            • 你可以只注入security.context。你不需要注入所有的服务容器。
            • @skonsoft,是的,你是对的。在我回答这个问题时,我对服务定位器反模式感到困惑。但是我还是没有更新答案,因为我当时想留下自己愚蠢的痕迹:)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多