【问题标题】:Error on form submission: The CSRF token is invalid. Please try to resubmit the form [duplicate]提交表单时出错:CSRF 令牌无效。请尝试重新提交表格[重复]
【发布时间】:2014-05-09 14:15:10
【问题描述】:

我一直在尝试提交一个将 Question 对象添加到数据库中的表单。

但每次我这样做时,都会出现错误“CSRF 令牌无效。请尝试重新提交表单”。

在表单的内容字段中,我附加了 this 插件,它是一个与 Stack Overflow 相同的编辑器。

在我的表单标签字段中,我附加了this 一个用于标签自动完成。

这是我的控制器代码:

/**
 * Creates a new Question entity.
 *
 * @Route("/ask", name="question_create")
 * @Method("POST")
 * @Template("VerySoftAskMeBundle:Question:ask.html.twig")
 */
public function createAction(Request $request) {
    $entity = new Question();
    $form = $this->createCreateForm($entity);
    $tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
    date_default_timezone_set('Asia/Manila');
    $entity->setDateOfPost(new \DateTime());

    $entity->setOwner($this->getUser());

        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($entity);
            $em->flush();

            return $this->redirect($this->generateUrl('question_show', array('id' => $entity->getId())));
        }


    return array(
        'entity' => $entity,
        'form' => $form->createView(),
        'tags' => $tags
    );
}

/**
 * Creates a form to create a Question entity.
 *
 * @param Question $entity The entity
 *
 * @return Form The form
 */
private function createCreateForm(Question $entity) {
    $form = $this->createForm(new QuestionType(), $entity, array(
        'action' => $this->generateUrl('question_create'),
        'method' => 'POST',
        'em' => $this->getDoctrine()->getEntityManager()
    ));

    $form->add('submit', 'submit', array('label' => 'Ask'));

    return $form;
}

/**
     * 
     * @Route("/ask", name="ask")
     * @Security( "has_role( 'ROLE_USER' )" )
     * @Method("GET")
     * @Template
     */
    public function askAction() {

        $tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
        $entity = new Question();
        $form = $this->createCreateForm($entity);

        return array(
            'entity' => $entity,
            'form' => $form->createView(),
            'tags' => $tags
        );
    }

我为我的标签字段制作了一个数据转换器,它将输入标签转换为标签对象。

class TagTransFormer implements DataTransformerInterface {

/**
 * @var ObjectManager
 */
private $om;

/**
 * @param ObjectManager $om
 */
public function __construct(ObjectManager $om) {
    $this->om = $om;
}

/**
 * Transforms an object (issue) to a string (number).
 *
 * @return ArrayCollection
 */
public function transform($tags) {

    return $tags;
}

/**
 * Transforms a string (number) to an object (issue).
 *
 * @param  string $number
 *
 * @return ArrayCollection
 *
 * @throws TransformationFailedException if object (issue) is not found.
 */
public function reverseTransform($ids) {

    $tags = array();

    if (!$ids) {
        return null;
    }

    $repo = $this->om
            ->getRepository('VerySoftAskMeBundle:Tag');

    $idsArray = explode(",", $ids);
    foreach ($idsArray as $id) {
        $tags[] = $repo->findOneByName($id);
    }
    return $tags;
}
}

这是我的表单类:

class QuestionType extends AbstractType {

/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options) {

    $entityManager = $options['em'];
    $transformer = new TagTransFormer($entityManager);

    $builder
            ->add('title', 'text')
            ->add('content', 'textarea')
            ->add($builder->create('tags', 'text')
                    ->addModelTransformer($transformer)
    );
}

/**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver) {
    $resolver->setDefaults(array(
                'data_class' => 'VerySoft\AskMeBundle\Entity\Question'
            ))
            ->setRequired(array(
                'em',
            ))
            ->setAllowedTypes(array(
                'em' => 'Doctrine\Common\Persistence\ObjectManager',
    ));
}

/**
 * @return string
 */
public function getName() {
    return 'verysoft_askmebundle_question';
}
}

我的树枝模板:

<div id="askDiv" style="padding-bottom: 90px;">
        {{ form_start(form, { 'attr' : { 'novalidate' : 'novalidate', 'class' : 'col-md-offset-3 form-control-static col-md-7' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-bottom: 30px;">
    <span class="askLabels col-lg-1 text-left">{{ form_label(form.title) }}</span>
            {{form_widget(form.title, { 'attr' : { 'class' : 'form-control col-lg-11' } })}}
</div>
        {{ form_widget(form.content, { 'attr' : { 'class' : 'col-lg-12' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-top: 20px;">
    <label class="col-lg-1 text-left askLabels" for="tagField">Tags</label>

    <div class="col-lg-8">
        {{ form_widget(form.tags) }}
    </div>
    {% if app.user.reputation >= 100 %}
    <a id="addTag" title="Add New Tag" data-toggle="tooltip modal" data-placement="left" class="col-lg-3" href="#"><i class="fa fa-plus-circle"></i></a>
    <div id="mymodal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                    <h4 class="modal-title" id="myModalLabel">Add New Tag</h4>
                </div>
                <div class="modal-body">
                    <label for="tagName">Tag Name: </label>
                    <input id="tagName" class="form-control" type="text"/>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-primary">Add Tag</button>
                </div>
            </div>
        </div>
    </div>

    {% endif %}


</div>
<div style="margin-top: 20px; ">
        {{ form_widget(form.submit, { 'attr' : { 'class' : 'col-md-offset-4 col-md-4  btn btn-primary' } }) }}
</div>

<p>
    title error{{ form_errors(form.title) }}
</p>
<p>
    content error{{ form_errors(form.content) }}
</p>
<p>
    tag error{{ form_errors(form.tags) }}
</p>
<p>
    form error{{ form_errors(form) }}
</p>

脚本:

$(document).ready(function(){
$("textarea").pagedownBootstrap();

    var zeTags = ["{{ tags|join('", "')|raw }}"];
    $('#verysoft_askmebundle_question_tags').tagit({
        availableTags: zeTags,
        tagLimit: 5,
        beforeTagAdded: function(event, ui) {
            if ($.inArray(ui.tagLabel, zeTags) == -1)
                return false;
        }
    });
});

【问题讨论】:

    标签: forms twitter-bootstrap symfony tag-it pagedown


    【解决方案1】:

    对于较新版本的 Symonfy,例如2.4+ 您将使用较新的form_end(form),它会自动呈现所有未呈现的字段以及 CSRF 令牌。

    根据documentation

    form_end() - Renders the end tag of the form and any fields that have not yet been rendered. This is useful for rendering hidden fields and taking advantage of the automatic CSRF Protection.
    

    【讨论】:

      【解决方案2】:

      你错过了

      {{ form_rest(form) }}
      

      Symfony2 有一种机制可以帮助防止跨站脚本:它们生成一个 CSRF 令牌,该令牌必须用于表单验证。在这里,在您的示例中,您没有使用form_rest(form) 显示(因此没有提交)它。基本上form_rest(form) 将“渲染”您之前未渲染但包含在您已传递给视图的表单对象中的每个字段。 CSRF 令牌就是这些值之一。

      【讨论】:

      • 嘿,成功了。谢谢!
      猜你喜欢
      • 2014-06-20
      • 2020-07-27
      • 2018-01-15
      • 1970-01-01
      • 1970-01-01
      • 2017-08-01
      • 2013-01-14
      • 2014-06-19
      • 2019-07-28
      相关资源
      最近更新 更多