首页 > 解决方案 > CSRF 无效,因为注册过程中有两个实体

问题描述

我有两个实体和一个表格用于注册过程。当我添加 csrf 令牌时,它可能适用于其中一个,而不适用于两者。

<form action="" method="post" class="registerForm" id="registerForm" novalidate>
    <div class="form-row">
        <div class="form-group col-lg-6">
            <input type="text" class="form-control inner-blue-shadow" name="company[name]" id="companyName" placeholder="Име на фирма" required/>
            <div class="invalid-feedback"></div>
            <div class="valid-feedback"></div>
        </div>
        <div class="form-group col-lg-6">
            <input type="text" class="form-control inner-blue-shadow" name="company[bulstat]" id="bulstat" placeholder="Булстат" required/>
            <div class="invalid-feedback"></div>
            <div class="valid-feedback"></div>
        </div>
    </div>
    <div class="form-group">
        <input type="text" class="form-control inner-blue-shadow" name="user[username]" id="username" placeholder="Потребителско име" required/>
        <div class="invalid-feedback"></div>
        <div class="valid-feedback"></div>
    </div>
    <div class="form-group">
        <input type="email" class="form-control inner-blue-shadow" name="user[email]" id="email" placeholder="Имейл адрес" required/>

    </div>
    <div class="form-group">
        <input type="password" class="form-control inner-blue-shadow" name="user[password]" id="password" placeholder="Парола" required/>
        <div class="invalid-feedback"></div>
        <div class="valid-feedback"></div>
    </div>
    {{ form_row(form._token) }}
    <div class="text-center"><button type="submit" id="registerButton">Create account</button></div>
</form>

输出是:“user__token”,据我所见,它会生成它,但仅影响两个实体之一的异常- 用户并且它不适用于另一个。

当我删除公司字段时,一切都像魅力一样。

表格是:

1.用户

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $schools = $this->schoolRepository->findAll();

    $builder
        ->add('username', TextType::class)
        ->add('email', EmailType::class)
        ->add('password', PasswordType::class)
}

/**
 * {@inheritdoc}
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle\Entity\User',
        'csrf_protection' => true,
        'csrf_field_name' => '_token',
        'csrf_token_id'   => 'task_item'
    ));
}

2.公司:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('name', TextType::class);
    $builder->add('bulstat', TextType::class);
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle\Entity\Company',
        'csrf_protection' => true,
        'csrf_field_name' => '_token',
        'csrf_token_id'   => 'task_item'
    ));
}

创建表单的控制器:

$company = new Company();
$companyForm = $this->createForm(CompanyType::class, $company);
$companyForm->handleRequest($request);

$user = new User();
$userForm = $this->createForm(UserType::class, $user);
$userForm->handleRequest($request);

我该如何解决?

标签: phpsymfonycsrf

解决方案


这基本上是一个如何将两个实体组合成一个形式的问题。还有其他问题可以解决这个问题,但有些问题有些陈旧且过时。这个问题也是一个没有利用 Symfony 所提供的优势并且比开发人员更努力地工作的例子。

具体来说,Symfony 开箱即用地处理 csrf,不需要特殊配置。你可以用它做更多的事情,但是从一个默认的工作实现开始,然后在必要时进行调整会更容易。以类似的方式,twig 具有表单的默认呈现。表单工作后,您可以使用各种样式工具使其看起来更漂亮。

首先简化您的 EntityType 类并添加 RegisterType:

class UserType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => User::class,
        ));
    }
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('username', TextType::class)
            ->add('email', EmailType::class)
            ->add('password', PasswordType::class);
    }
}
class CompanyType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Company::class,
        ));
    }
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('bulstat', TextType::class);
    }
}
class RegisterType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('user', UserType::class)
            ->add('company', CompanyType::class)
            ->add('register', SubmitType::class);
    }
}

现在调整控制器代码并使用默认的表单渲染:

    public function register(Request $request)
    {
        $user = new User();
        $company = new Company();
        $register = ['user' => $user, 'company' => $company];

        $form = $this->createForm(RegisterType::class, $register);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            dump($user);
            dump($company);
        }

        return $this->render('register.html.twig',['form' => $form->createView()]);
    }
# register.html.twig
{% extends 'base.html.twig' %}
{% block body %}
    <h1>Register</h1>
    {{ form(form) }}
{% endblock %}

此时您应该有一个工作表格。然后,您可以添加验证和持久性以及使表单看起来不错。


推荐阅读