簡體   English   中英

Symfony2 注銷事件偵聽器問題

[英]Symfony2 Logout Event Listener Issue

我正在將審計日志添加到 Symfony2 項目中,該項目將所有頁面加載和發布請求記錄到自定義審計表中。 該項目使用 Symfony2 的默認注銷路由(訪問 /logout),它會破壞會話然后重定向到 /login 路由。

為 onKernelRequest 設置了一個事件偵聽器,然后將正確的數據寫入表中。 在 security.yml 文件中,我為注銷路由列出了以下內容。

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

除了注銷事件,審計日志對所有頁面都工作正常。 注銷后,我嘗試訪問分析器,然后從側欄中的“最后 10 個”選項中選擇“/注銷”操作。 單擊“事件”時,它會列出 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();
    }
}

服務.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 }

掛鈎 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]

因此,您真正需要做的就是使用logout方法從您的AuditListener實現LogoutHandlerInterface ,然后在配置中注冊handlers參數

由於我不清楚您的Audit logging服務,我想,注銷事件事先發生。 因此,您應該嘗試通過實現另一個實現LogoutHandlerInterface並依賴於您的Audit logging服務的LogoutHandler服務來調用您的Audit logging Audit logging服務。

在我們看到日志記錄中發生的事情后,我們可以得到一個清晰的想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM