Symfony2注销事件监听器问题

时间:2016-07-26 14:45:03

标签: php session symfony-2.8

我正在努力将审核日志记录添加到Symfony2项目,该项目记录所有页面加载并将请求发布到自定义审核表中。该项目使用Symfony2的默认注销路由(访问/注销),该路由销毁会话,然后重定向到/ login路由。

为onKernelRequest设置了一个事件监听器,然后将正确的数据写入表中。在security.yml文件中,我列出了以下注销路由。

security:
    firewalls:
        main:
            logout:
                path: /logout
                target: /login

审核日志记录适用于除注销事件之外的所有页面。退出后我尝试访问了探查器,然后选择了' / logout'来自"最后10"侧栏中的选项。点击" Events"这列出了kernel.request的默认Symfony事件,例如DebugHandler和ProfileListener,但我的自定义回调显示在" Not Called Listeners"标签

有一个success_handler可以添加到security.yml文件中,但是我需要一个可以在会话被销毁之前运行我的事件监听器的方法。有没有办法让现有的侦听器在Symfony执行注销之前记录注销事件?

修改

<?php

// src/AuditBundle/EventListener/AuditListener.php
namespace AuditBundle\EventListener;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use AuditBundle\Entity\AuditLog;

class AuditListener
{
    protected $requestStack;
    protected $em;
    protected $tokenStorage;
    protected $authorizationChecker;

    public function __construct(RequestStack $requestStack, \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage $tokenStorage, $authorizationChecker, \Doctrine\ORM\EntityManager $em = NULL)
    {
        $this->requestStack = $requestStack;
        $this->em = $em;
        $this->tokenStorage = $tokenStorage;
        $this->authorizationChecker = $authorizationChecker;
    }

    public function onKernelRequest(GetResponseEvent $response)
    {
        $request = $response->getRequest();
        if ( strpos($request->getRequestUri(), 'fonts') !== false)
            return;
        if ( strpos($request->getRequestUri(), 'css') !== false)
            return;
        if ( strpos($request->getRequestUri(), '_wdt') !== false)
            return;
        if ( strpos($request->getRequestUri(), 'js') !== false)
            return;

        if ( strpos($request->getRequestUri(), '_profiler') !== false)
            return;

        $this->log('Request', $request);
    }

    public function postUpdate(\Doctrine\ORM\Event\LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $this->em = $args->getEntityManager();
        $className = $this->em->getClassMetadata(get_class($entity))->getName();
        if ($entity instanceof \AuditBundle\Entity\AuditLog)
            return;
        $this->log($className.' Updated', $this->requestStack->getCurrentRequest(), $entity);
    }

    public function postPersist(\Doctrine\ORM\Event\LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $this->em = $args->getEntityManager();
        $className = $this->em->getClassMetadata(get_class($entity))->getName();
        if ($entity instanceof \AuditBundle\Entity\AuditLog)
            return;
        $this->log($className.' Created', $this->requestStack->getCurrentRequest(), $entity);
    }

    public function postDelete(\Doctrine\ORM\Event\LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $this->em = $args->getEntityManager();
        $className = $this->em->getClassMetadata(get_class($entity))->getName();
        if ($entity instanceof \AuditBundle\Entity\AuditLog)
            return;
        $this->log($className.' Deleted', $this->requestStack->getCurrentRequest());
    }

    protected function log($message, $request, $entity = NULL)
    {
        $log = new AuditLog();
        $log->setType($request->getRealMethod());
        if ($this->authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY'))
        {
            $log->setUser($this->tokenStorage->getToken()->getUser());
        }
        if ($entity)
        {
            $log->setEntityId($entity->getId());
        }

        $log->setUriString($request->getRequestUri());
        $log->setMessage($message);
        $log->setDatetime(new \DateTime());
        $log->setIp($request->getClientIp());
        $log->setBrowser(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
        $this->em->persist($log);
        $this->em->flush();
    }
}

services.yml

services:
    audits.audit_listener:
        class: AuditBundle\EventListener\AuditListener
        arguments: [@request_stack, @security.token_storage, @security.authorization_checker, @doctrine.orm.entity_manager]
        tags:
            - { name: kernel.event_listener, event: kernel.request }

2 个答案:

答案 0 :(得分:8)

挂钩Symfony注销事件的最佳方法是像这样实现LogoutHandlerInterface

事件监听器:

<?php

namespace AppBundle\EventListener;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;

class MyListener implements LogoutHandlerInterface {

    public function logout(Request $Request, Response $Response, TokenInterface $Token) {

        // Your handling here

        }

}

配置:

services:
    appbundle_mylistener:
        class: AppBundle\EventListener\MyListener

security:
    firewalls:
        main:
            logout:
                handlers: [appbundle_mylistener]

修改

所以你真正需要做的就是使用LogoutHandlerInterface函数实现AuditListener中的logout,然后在配置中注册handlers参数

答案 1 :(得分:0)

由于我不清楚您的Audit logging服务,我猜,退出事件是事先发生的。因此,您应该尝试通过实施另一个Audit logging服务来调用LogoutHandler服务,该服务实现LogoutHandlerInterface并依赖于您的Audit logging服务。

在我们看到日志记录中发生了什么后,我们可以得到一个清晰的想法。