将安全用户的名称传递给Symfony2

时间:2016-06-08 13:53:10

标签: symfony security service gedmo-loggable

我正在使用Gedmo Loggable来跟踪用户对实体所做的更改。默认情况下,不会为每次更改存储用户名,但必须将其提供给侦听器。

这方面的一个例子可以在Loggable的文档中找到:

  $loggableListener = new Gedmo\Loggable\LoggableListener;
  $loggableListener->setAnnotationReader($cachedAnnotationReader);
  $loggableListener->setUsername('admin');
  $evm->addEventSubscriber($loggableListener);

这对我不起作用有两个原因:

  1. 我在services.yml中注册了监听器,而不是在控制器
  2. 我不希望存储示例中的预先知道的用户名,而是存储用户的用户名
  3. loggableListener的方法setUsername要求字符串或带有方法getUsername的对象提供字符串。

    如何将任何一个传递给侦听器?我找到了传递security_token的方法,但这还不够。我现在拥有的是:

    (...)
    gedmo.listener.loggable:
    class: Gedmo\Loggable\LoggableListener
    tags:
        - { name: doctrine.event_subscriber, connection: default }
    calls:
        - [ setAnnotationReader, [ "@annotation_reader" ] ]
        #- [ setUsername, [ "A fixed value works" ] ]
        - [ setUserValue, [ @security.??? ] ]
    

    我也在使用Blameable,并为类似的问题找到了一个很好的解决方法(整个监听器被覆盖)。我试图对Loggable做同样的事情,但这看起来有点复杂。

    主要问题:如何将安全用户对象(或其用户名)传递给services.yml中的侦听器?

    更新

    Matteo向我展示了如何将函数的结果作为参数传递给侦听器。这几乎解决了这个问题。还有另一项服务,在给定token_storage时提供用户名。但这意味着我需要将一个参数传递给一个服务,该服务作为参数提供给另一个服务。这个例子将解释:

    - [ setUsername, [ "@=service('gedmo.listener.blameable').getUsername( @security.token_storage )" ] ]
    

    现在的问题是,在此上下文中不接受@ security.token_storage。如何将参数传递给方法getUsername()?

3 个答案:

答案 0 :(得分:1)

您可以使用Symfony Service Expressions,例如,您可以尝试以下操作:

gedmo.listener.loggable:
class: Gedmo\Loggable\LoggableListener
tags:
    - { name: doctrine.event_subscriber, connection: default }
calls:
    - [ setAnnotationReader, [ "@annotation_reader" ] ]
    - [ setUserValue, ["@=service('security.token_storage').getToken()->getUser()->getUsername()"] ]

但在某些情况下,用户可以是null,因此您可以使用?条件(请参阅文档)。

希望这个帮助

答案 1 :(得分:0)

我认为将authed用户注入服务是不可能的。但是您可以注入令牌存储:@security.token_storage(在symfony 2.6之前,您必须使用@security.context而不是@security.token_storage) 在您的服务(LoggableListener)中,您将能够获得如下的authed用户名: $tokenStorage->getToken()->getUser()->getUsername()

答案 2 :(得分:0)

我遇到了同样的问题,我通过创建stofDoctrineExtensionsBundle中的记录器侦听器来解决它。

为此,我创建了这个文件:

//src/AppBundle/Listener/LoggerListener 
<?php

namespace AppBundle\Listener;

use Gedmo\Loggable\LoggableListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

/**
 * LoggerListener
 *
 * @author Alexandre Tranchant <alexandre.tranchant@gmail.com>
 * @author Christophe Coevoet <stof@notk.org>
 */
class LoggerListener implements EventSubscriberInterface
{
    /**
     * @var AuthorizationCheckerInterface
     */
    private $authorizationChecker;
    /**
     * @var TokenStorageInterface
     */
    private $tokenStorage;
    /**
     * @var LoggableListener
     */
    private $loggableListener;

    /**
     * LoggerListener constructor.
     *
     * @param LoggableListener $loggableListener
     * @param TokenStorageInterface|null $tokenStorage
     * @param AuthorizationCheckerInterface|null $authorizationChecker
     */
    public function __construct(LoggableListener $loggableListener, TokenStorageInterface $tokenStorage = null, AuthorizationCheckerInterface $authorizationChecker = null)
    {
        $this->loggableListener = $loggableListener;
        $this->tokenStorage = $tokenStorage;
        $this->authorizationChecker = $authorizationChecker;
    }
    /**
     * Set the username from the security context by listening on core.request
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
            return;
        }
        if (null === $this->tokenStorage || null === $this->authorizationChecker) {
            return;
        }
        $token = $this->tokenStorage->getToken();
        if (null !== $token && $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
            $this->loggableListener->setUsername($token);
        }
    }
    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::REQUEST => 'onKernelRequest',
        );
    }
}

然后我在services.yml文件中声明了这个监听器。

services:
    #Loggable
    gedmo.listener.loggable:
            class: Gedmo\Loggable\LoggableListener
            tags:
                - { name: doctrine.event_subscriber, connection: default }
            calls:
                - [ setAnnotationReader, [ "@annotation_reader" ] ]

    # KernelRequest listener
    app.listener.loggable:
        class: AppBundle\Listener\LoggerListener
        tags:
            # loggable hooks user username if one is in token_storage or authorization_checker
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest}
        arguments:
            - '@gedmo.listener.loggable'
            - '@security.token_storage'
            - '@security.authorization_checker'

正如您在此转储屏幕截图中看到的,它可以正常工作: Screenshot of Log dump