首页 > 解决方案 > 为什么我会收到“加载 Web 调试工具栏时出错”。何时使用此事件订阅者?

问题描述

我正在创建配置的维护页面。

我创建了一个事件订阅者:

    public function onKernelRequest(RequestEvent $event)
    {
        $maintenance = $this->container->hasParameter('maintenance') ? $this->container->getParameter('maintenance') : false;
        $underMaintenanceUntil = $this->container->hasParameter('underMaintenanceUntil') ? $this->container->getParameter('underMaintenanceUntil') : false;

        if (!$event->isMasterRequest()){
            return;
        }

        $debug = in_array($this->container->get('kernel')->getEnvironment(), ['test','dev']);
        $uri = $event->getRequest()->getRequestUri();

        if ($uri == '/login' || $uri == '/logout') {

            return;
        }

        if ($maintenance && !$debug && !$this->container->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
            $engine = $this->container->get('twig');

            $content = $engine->render('pages/maintenance.html.twig', array('underMaintenanceUntil' => $underMaintenanceUntil));
            $event->setResponse(new Response($content, 503));
            $event->stopPropagation();
        }
    }

并且探查器栏不起作用。我明白了

加载 Web 调试工具栏时出错。

在日志中:

[申请] 10月5日 08:24:41 |INFO | 请求匹配的路由“_wdt”。method="GET" request_uri="https://localhost:8001/_wdt/914ef7" route="_wdt" route_parameters={"_controller":"web_profiler.controller.profiler::toolbarAction","_route":"_wdt" ,"token":"914ef7"} [应用] Oct 5 08:24:41 |CRITICA| 请求未捕获的 PHP 异常 Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException:“令牌存储不包含身份验证令牌。一个可能的原因可能是没有为此 URL 配置防火墙。” 在 /home/marcin/projects/indali/vendor/symfony/security-core/Authorization/AuthorizationChecker.php 第 52 行

即使我输入/loginpage 我也会得到同样的错误。如果它是登录uri,这if ($uri == '/login' || $uri == '/logout') {return;}是否应该防止不执行进一步的代码?

$this->container->get('security.authorization_checker')->isGranted('ROLE_ADMIN')会产生我的错误,因为在开发防火墙中没有身份验证令牌。我可以检查令牌是否存在,但为什么我的代码不起作用?

标签: phpsymfonysymfony-securitysymfony-eventdispatcher

解决方案


您的代码不起作用,因为探查器是对/loginor 或的主请求的单独请求/logout

分析器栏通过 AJAX 请求加载到不同的 URL。如果您检查您的安全配置,默认值通常是:

dev:
    pattern: '^/(_(profiler|wdt)|css|images|js)/'
    security: false

Profiler 调用是通过_profiler或的调用_wdt。因此,您的检查loginlogoutURL 对此根本没有用。它会影响主请求,但不会影响分析器栏请求:

一些选项是,从更差到更好:

检查令牌

正如您所提到的,请检查令牌是否不为空,但这可能无法按您的预期工作,因为它最终会允许匿名用户在“维护”时访问您的站点。

检查 URL 路径

便宜又简单:对照dev模式检查请求路径(或_(profiler|wdt)至少对照)。这应该很容易合并到您的代码中,但是如果您最终添加另一个非安全防火墙,将来可能会出现问题:

if (preg_match('/^\/(logout|login|_(wdt|profiler))/', $uri) {
         return;
}

检查FirewallConfig请求

如果你想干净利落地做,你应该注入 FirewallMap你的事件订阅者,并为请求获取防火墙。

一个简单的示例,您需要根据自己的需要进行调整:

use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component;

class FooSubscriber implements Component\EventDispatcher\EventSubscriberInterface
{

    private Security\FirewallMap  $firewallMap;

    public function __construct(Security\FirewallMap $firewallMap)
    {
        $this->firewallMap = $firewallMap;
    }

    public static function getSubscribedEvents(): array
    {
        return [Component\HttpKernel\KernelEvents::REQUEST => 'onKernelRequest'];
    }

    public function onKernelRequest(Component\HttpKernel\Event\RequestEvent $event): void
    {
        if (!$event->isMasterRequest()) {
            return;
        }

        $config = $this->firewallMap->getFirewallConfig($event->getRequest());

        if (!$config instanceof Security\FirewallConfig || (!$config->isSecurityEnabled() || $config->allowsAnonymous())) {
            return;
        }
    }
}

由于FirewallMap不是自动连接的,您需要配置服务以显式注入它:

// services.php

$services->set(FooSubscriber::class)
             ->args([service('security.firewall.map')]);

或在老式 YAML 中:

# services.yaml
services:
    App\FooSubscriber:
        arguments:
            - '@security.firewall.map'

在您的情况下,您似乎正在取消依赖注入并直接检索容器。尽管这是一种不好的做法,如果可能的话,您应该更改它,使用您当前的代码,您可以简单地从$this-container->get('security.firewall.map');


推荐阅读