草庐IT

php - Symfony2 注销事件监听器问题

coder 2024-04-12 原文

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

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

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

除注销事件外,所有页面的审核日志记录都正常工作。注销后,我尝试访问探查器,然后从侧边栏的“最后 10 个”选项中选择“/注销”操作。单击“事件”时,它会列出 kernel.request 的默认 Symfony 事件,例如 DebugHandler 和 ProfileListener,但我的自定义回调显示在“未调用的监听器”选项卡下。

有一个 success_handler 可以添加到 security.yml 文件中,但是我需要一个可以在 session 被销毁之前运行我的事件监听器的方法。有没有办法让现有的监听器在 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 配置中的参数

关于php - Symfony2 注销事件监听器问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38593068/

有关php - Symfony2 注销事件监听器问题的更多相关文章

  1. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  2. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  3. ruby-on-rails - 事件管理员和自定义方法 - 2

    这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什

  4. ruby-on-rails - 在不重新查询数据库的情况下重新排序 Rails 中的事件记录? - 2

    例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果

  5. ruby-on-rails - Ruby 长时间运行的进程对队列事件使用react - 2

    我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby​​脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几

  6. ruby-on-rails - 使用 Rails 事件记录获取二级模型 - 2

    我有一个帖子属于城市的关系,城市又属于一个州,例如:classPost现在我想找到所有帖子及其所属的城市和州。我编写了以下查询来获取带有城市的帖子,但不知道如何在同一查找器中获取带有城市的相应州:@post=Post.find:all,:include=>[:city]感谢任何帮助。谢谢。 最佳答案 Post.all(:include=>{:city=>:state}) 关于ruby-on-rails-使用Rails事件记录获取二级模型,我们在StackOverflow上找到一个类似的问

  7. ruby-on-rails - Devise 在更改密码后注销用户 - 2

    我正在使用devise,当用户更改密码时,网站会将他们注销。我在网上读到,添加sign_in可以解决问题但不起作用,并且当密码更改时用户会注销。这是我的代码if@user.errors[:base].empty?and@user.update_attributes(params[:user])sign_in(current_user,:bypass=>true)flash[:success]="Useraccounthasbeensuccessfullyupdated"redirect_toedit_user_path(params[:site_id],@user)elserender

  8. ruby - 在没有数据库的情况下伪造一个事件记录模型 - 2

    我觉得我错过了什么。我正在编写一个ruby​​gem,它允许与事件记录进行交互,作为其主要功能的附加功能。在为其编写测试用例时,我需要能够指定虚拟事件记录模型来测试此功能。如果我可以获得一个事件记录模型的实例,它不需要与数据库的任何连接,可以有关系,所有这些东西,但不需要我在数据库中设置表,那就太棒了。我对测试还很陌生,在Rails测试之外我也很陌生,但似乎我应该能够相当轻松地完成类似的事情,但我什么也没找到。谁能告诉我我错过了什么?我看过工厂、制造商、固定装置,所有这些似乎都想达到目标。人们如何在您只需要AR对象进行测试的地方测试gem? 最佳答案

  9. ruby-on-rails - 在事件记录库中添加某些方法的首选方法是什么? - 2

    我想创建一个模块,为从事件记录库继承的类提供一些通用方法。以下是我们可以实现的两种方式。1)moduleCommentabledefself.extended(base)base.class_evaldoincludeInstanceMethodsextendClassMethodsendendmoduleClassMethodsdeftest_commentable_classmethodputs'testclassmethod'endendmoduleInstanceMethodsdeftest_commentable_instance_methodputs'testinstanc

  10. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

随机推荐