为什么得到“加载Web调试工具栏时发生错误”使用此事件订阅服务器时? 检查令牌检查URL路径检查FirewallConfig的请求

问题描述

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

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

    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 |信息|请求匹配的路线“ _wdt”。 method =“ GET” request_uri =“ https:// localhost:8001 / _wdt / 914ef7” route =“ _ wdt” route_parameters = {“ _ controller”:“ web_profiler.controller.profiler :: toolbarAction”,“ _ route”:“ _ wdt”,“令牌”:“ 914ef7”} [应用程序] 10月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行

即使我输入/login页面,我也会遇到相同的错误。 if ($uri == '/login' || $uri == '/logout') {return;}是否应该阻止不执行其他代码(如果它是登录uri)?

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

解决方法

您的代码不起作用,因为事件探查器是从主请求到/login/logout的单独请求。

分析器栏通过AJAX请求加载到其他URL。如果您检查安全配置,则默认通常为:

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

Profiler调用是通过_profiler_wdt进行的。因此,检查loginlogout URL对此根本没有用。它会影响主请求,但不会影响探查器栏请求:

从更坏到更好,有些选择是

检查令牌

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

检查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');

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...