将 Symfony Form 组件与 security-csrf 独立使用 - 提交时出错

Using Symfony Form component standalone with security-csrf - error on submission

我有一个关于 symfony/form 用作独立组件和 security-csrf 运行 PHP 内置服务器的问题。我几乎不记得 Symfony 框架有过这样的问题。

symfony/form 设置为独立组件时,我为 v4.2 和 v5.1 都尝试了此代码 https://github.com/xmgcoyi/standalone-forms/tree/4.2+twig. A rewrite of webmozart's example mentioned here https://symfony.com/doc/current/components/form.html

csrf 令牌是使用 twig-bridge 生成的,但是在提交表单时 - 在调用时出现 $form->isValid() - invalid csrf 错误。

默认启用 csrf 保护,设置为 false - 表单提交。

尝试使用 NativeSessionTokenStorageSessionTokenStorage + Session of HttpFoundation 两种设置的 CSRF 组件。

你能给我一些提示,告诉我哪里做错了吗?

P.S. 提交时出现 csrf 错误的代码示例:

UPD 上面的应用程序运行良好,问题出在充满垃圾的浏览器存储中。

$formFactory->createBuilder(FormType::class, null, ['csrf_protection' => false]) 中设置为 false 提交表单

这是一个猜测,但 4.2 链接的 repo 有:

$csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);
$csrfTokenManager = new CsrfTokenManager();

两个令牌管理器。一个用于 twig 表单引擎,一个用于表单工厂扩展。这似乎不是一件合理的事情。

这是更新后的 5.1 工作示例。我从您的链接回购协议中进一步剥离了它。但我唯一真正改变的是令牌管理器。

# index.php
require_once '../vendor/autoload.php';

$app = new App();
$app->run();

final class App
{
    public function run()
    {
        $csrfGenerator = new UriSafeTokenGenerator();
        $csrfStorage = new NativeSessionTokenStorage();
        $csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);

        $twig = new Environment(new FilesystemLoader([
            '../templates',
            '../vendor/symfony/twig-bridge/Resources/views/Form',
        ]));

        $formEngine = new TwigRendererEngine(['form_div_layout.html.twig'], $twig);

        $twig->addRuntimeLoader(new FactoryRuntimeLoader([
            FormRenderer::class => function () use ($formEngine,$csrfManager) {
                return new FormRenderer($formEngine, $csrfManager);
            },
        ]));
        $twig->addExtension(new TranslationExtension());
        $twig->addExtension(new FormExtension());

        $formFactory = Forms::createFormFactoryBuilder()
            ->addExtension(new CsrfExtension($csrfManager))
            //->addExtension(new ValidatorExtension($validator))
            ->getFormFactory();

        $form = $formFactory->createBuilder()
            ->add('firstName', TextType::class)
            ->getForm();

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $form->submit($_POST[$form->getName()]); // form
            if ($form->isValid()) {
                dump('form is valid');
            }
        }
        echo $twig->render('index.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}

composer.json就是:

{
    "require": {
        "symfony/form": "^5.1",
        "symfony/twig-bridge": "^5.1",
        "symfony/translation": "^5.1",
        "symfony/security-csrf": "^5.1"
    },
    "require-dev": {
        "symfony/var-dumper": "^5.1"
    }
}

如果您仍然遇到问题,那么我建议您追踪会话的存储位置,然后验证是否正确存储了 csrf 令牌。它应该看起来像:

_csrf|a:1:{s:4:"form";s:43:"9v1tUNe3J3eYVOmEPwVdz5_iISfzBg8Qa9pLMV8tSN4";}

这实际上是一种将 twig 系统用于独立表单的有趣练习。谢谢