Symfony2-过载注册表导致CSRF错误(添加了github repo)


Symfony2 - Overload registration form causes CSRF errors (added github repo)

我目前正在重载SonataUser注册表单,以便在人们创建帐户时可以拥有自己的自定义表单。

我已经正确地重载了所有内容(处理程序、表单类型、控制器和小树枝模板)。但是,当我发送表单时,我只会返回数据,并且不会创建新用户。因此,我进行了调查,发现当我回应这个时

var_dump($this->form->getErrors());

我得到一个错误,说CSRF令牌无效。我正在使用Symfony 2.4.2sonata user 2.2.x-dev

我将向您展示我已过载的所有类。目前,它们大多是从父母那里复制粘贴的。

这是我的表单处理程序

<?php
/*
 * This file is part of the Sonata package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */
namespace Application'Sonata'UserBundle'Form'Handler;
use Symfony'Component'Form'Form;
use Symfony'Component'HttpFoundation'Request;
use FOS'UserBundle'Model'UserInterface;
use FOS'UserBundle'Model'UserManagerInterface;
use FOS'UserBundle'Form'Handler'RegistrationFormHandler as BaseHandler;
use Symfony'Component'Form'FormInterface;

use FOS'UserBundle'Mailer'MailerInterface;
use FOS'UserBundle'Util'TokenGeneratorInterface;

/**
 *
 * This file is an adapted version of FOS User Bundle RegistrationFormHandler class
 *
 *    (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
 */
class RegistrationFormHandler extends BaseHandler
{
    protected $request;
    protected $userManager;
    protected $form;
    protected $mailer;
    protected $tokenGenerator;
    public function __construct(FormInterface $form, Request $request, UserManagerInterface $userManager, MailerInterface $mailer, TokenGeneratorInterface $tokenGenerator)
    {
        $this->form = $form;
        $this->request = $request;
        $this->userManager = $userManager;
        $this->mailer = $mailer;
        $this->tokenGenerator = $tokenGenerator;
    }
    /**
     * @param boolean $confirmation
     */
    public function process($confirmation = false)
    {
        $user = $this->createUser();
        $this->form->setData($user);
        if ('POST' === $this->request->getMethod()) {
            $this->form->bind($this->request);
            if ($this->form->isValid()) {
                var_dump('working !!');
                $this->onSuccess($user, $confirmation);
                return true;
            }
            var_dump($this->form->getErrors());
        }
        return false;
    }
    /**
     * @param boolean $confirmation
     */
    protected function onSuccess(UserInterface $user, $confirmation)
    {
        if ($confirmation) {
            $user->setEnabled(false);
            if (null === $user->getConfirmationToken()) {
                $user->setConfirmationToken($this->tokenGenerator->generateToken());
            }
            $this->mailer->sendConfirmationEmailMessage($user);
        } else {
            $user->setEnabled(true);
        }
        $this->userManager->updateUser($user);
    }
    /**
     * @return UserInterface
     */
    protected function createUser()
    {
        return $this->userManager->createUser();
    }
}

这是我的表格类型:

<?php
/*
 * This file is part of the FOSUserBundle package.
 *
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Application'Sonata'UserBundle'Form'Type;
use Entities'User;
use Symfony'Component'Form'AbstractType;
use Symfony'Component'Form'FormBuilderInterface;
use Symfony'Component'OptionsResolver'OptionsResolverInterface;
use Sonata'UserBundle'Model'UserInterface;
class RegistrationFormType extends AbstractType
{
    private $class;
    /**
     * @var array
     */
    protected $mergeOptions;
    /**
     * @param string $class        The User class name
     * @param array  $mergeOptions Add options to elements
     */
    public function __construct($class, array $mergeOptions = array())
    {
        $this->class        = $class;
        $this->mergeOptions = $mergeOptions;
    }
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('username', null, array_merge(array(
                'label' => 'form.username',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('email', 'email', array_merge(array(
                'label' => 'form.email',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('plainPassword', 'repeated', array_merge(array(
                'type' => 'password',
                'required' => true,
                'options' => array('translation_domain' => 'SonataUserBundle'),
                'first_options' => array_merge(array(
                    'label' => 'form.password',
                ), $this->mergeOptions),
                'second_options' => array_merge(array(
                    'label' => 'form.password_confirmation',
                ), $this->mergeOptions),
                'invalid_message' => 'fos_user.password.mismatch',
            ), $this->mergeOptions))
            ->add('lastName', null, array_merge(array(
                'label' => 'form.label_lastname',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('firstName', null, array_merge(array(
                'label' => 'form.label_firstname',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('date_of_birth', 'birthday', array_merge(array(
                'label' => 'form.label_date_of_birth',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('gender', 'sonata_user_gender', array(
                'label'    => 'form.label_gender',
                'required' => true,
                'translation_domain' => 'SonataUserBundle',
                'choices' => array(
                    UserInterface::GENDER_FEMALE => 'gender_female',
                    UserInterface::GENDER_MALE   => 'gender_male',
                )
            ))
            ->add('phone', null, array_merge(array(
                'label' => 'form.label_phone',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('address', null, array_merge(array(
                'label' => 'form.address',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('city', null, array_merge(array(
                'label' => 'form.city',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
            ->add('state', 'choice', array_merge(array(
                'label' => 'form.state',
                'translation_domain' => 'SonataUserBundle',
                'multiple' => false,
                'expanded' => false
            ), $this->mergeOptions))
            ->add('country', 'choice', array_merge(array(
                'label' => 'form.country',
                'translation_domain' => 'SonataUserBundle',
                'multiple' => false,
                'expanded' => false
            ), $this->mergeOptions))
            ->add('postalCode', null, array_merge(array(
                'label' => 'form.postalCode',
                'translation_domain' => 'SonataUserBundle',
            ), $this->mergeOptions))
//            ->add('children', 'collection', array_merge(array(
//                'type' => new ChildFormType('Application'Sonata'UserBundle'Entity'User'),
//                'translation_domain' => 'SonataUserBundle',
//                'allow_add' => true,
//                'allow_delete' => true,
//                'by_reference' => false,
//            ), $this->mergeOptions))


        ;
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => $this->class,
            'intention'  => 'registration',
        ));
    }
    public function getName()
    {
        return 'sonata_user_registration';
    }
}

这是我的注册控制器

<?php
/*
 * This file is part of the Sonata package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Application'Sonata'UserBundle'Controller;
use Symfony'Component'DependencyInjection'ContainerAware;
use Symfony'Component'HttpFoundation'Request;
use Symfony'Component'HttpFoundation'Response;
use Symfony'Component'HttpFoundation'RedirectResponse;
use Symfony'Component'HttpKernel'Exception'NotFoundHttpException;
use Symfony'Component'Security'Core'Exception'AccessDeniedException;
use Symfony'Component'Security'Core'Exception'AccountStatusException;
use FOS'UserBundle'Model'UserInterface;
/**
 * Class SonataRegistrationController
 *
 * This class is inspired from the FOS RegistrationController
 *
 * @package Sonata'UserBundle'Controller
 *
 * @author Hugo Briand <briand@ekino.com>
 */
class RegistrationFOSUser1Controller extends ContainerAware
{
    public function registerAction()
    {
        $user = $this->container->get('security.context')->getToken()->getUser();
        if ($user instanceof UserInterface && 'POST' === $this->container->get('request')->getMethod()) {
            $this->container->get('session')->getFlashBag()->set('sonata_user_error', 'sonata_user_already_authenticated');
            $url = $this->container->get('router')->generate('sonata_user_profile_show');
            return new RedirectResponse($url);
        }
        $form = $this->container->get('sonata.user.registration.form');
        $formHandler = $this->container->get('sonata.user.registration.form.handler');
        $confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
        $process = $formHandler->process($confirmationEnabled);
        var_dump(0);
        if ($process) {
            var_dump(1);
            exit();
            $user = $form->getData();
            $authUser = false;
            if ($confirmationEnabled) {
                $this->container->get('session')->set('fos_user_send_confirmation_email/email', $user->getEmail());
                $route = 'fos_user_registration_check_email';
            } else {
                $authUser = true;
                $route = $this->container->get('session')->get('sonata_basket_delivery_redirect', 'sonata_user_profile_show');
                $this->container->get('session')->remove('sonata_basket_delivery_redirect');
            }
            $this->setFlash('fos_user_success', 'registration.flash.user_created');
            $url = $this->container->get('session')->get('sonata_user_redirect_url');
            if (null === $url || "" === $url) {
                $url = $this->container->get('router')->generate($route);
            }
            $response = new RedirectResponse($url);
            if ($authUser) {
                $this->authenticateUser($user, $response);
            }
            return $response;
        }
        $this->container->get('session')->set('sonata_user_redirect_url', $this->container->get('request')->headers->get('referer'));
        return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:register.html.'.$this->getEngine(), array(
            'form' => $form->createView(),
        ));
    }
    /**
     * Tell the user to check his email provider
     */
    public function checkEmailAction()
    {
        $email = $this->container->get('session')->get('fos_user_send_confirmation_email/email');
        $this->container->get('session')->remove('fos_user_send_confirmation_email/email');
        $user = $this->container->get('fos_user.user_manager')->findUserByEmail($email);
        if (null === $user) {
            throw new NotFoundHttpException(sprintf('The user with email "%s" does not exist', $email));
        }
        return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:checkEmail.html.'.$this->getEngine(), array(
            'user' => $user,
        ));
    }
    /**
     * Receive the confirmation token from user email provider, login the user
     */
    public function confirmAction($token)
    {
        $user = $this->container->get('fos_user.user_manager')->findUserByConfirmationToken($token);
        if (null === $user) {
            throw new NotFoundHttpException(sprintf('The user with confirmation token "%s" does not exist', $token));
        }
        $user->setConfirmationToken(null);
        $user->setEnabled(true);
        $user->setLastLogin(new 'DateTime());
        $this->container->get('fos_user.user_manager')->updateUser($user);
        if ($redirectRoute = $this->container->getParameter('sonata.user.register.confirm.redirect_route')) {
            $response = new RedirectResponse($this->container->get('router')->generate($redirectRoute, $this->container->getParameter('sonata.user.register.confirm.redirect_route_params')));
        } else {
            $response = new RedirectResponse($this->container->get('router')->generate('fos_user_registration_confirmed'));
        }
        $this->authenticateUser($user, $response);
        return $response;
    }
    /**
     * Tell the user his account is now confirmed
     */
    public function confirmedAction()
    {
        $user = $this->container->get('security.context')->getToken()->getUser();
        if (!is_object($user) || !$user instanceof UserInterface) {
            throw new AccessDeniedException('This user does not have access to this section.');
        }
        return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:confirmed.html.'.$this->getEngine(), array(
            'user' => $user,
        ));
    }
    /**
     * Authenticate a user with Symfony Security
     *
     * @param 'FOS'UserBundle'Model'UserInterface        $user
     * @param 'Symfony'Component'HttpFoundation'Response $response
     */
    protected function authenticateUser(UserInterface $user, Response $response)
    {
        try {
            $this->container->get('fos_user.security.login_manager')->loginUser(
                $this->container->getParameter('fos_user.firewall_name'),
                $user,
                $response);
        } catch (AccountStatusException $ex) {
            // We simply do not authenticate users which do not pass the user
            // checker (not enabled, expired, etc.).
        }
    }
    /**
     * @param string $action
     * @param string $value
     */
    protected function setFlash($action, $value)
    {
        $this->container->get('session')->getFlashBag()->set($action, $value);
    }
    protected function getEngine()
    {
        return $this->container->getParameter('fos_user.template.engine');
    }
}

以下是我的服务:

sonata.user.registration.form.type:
    class: Application'Sonata'UserBundle'Form'Type'RegistrationFormType
    arguments: [ "%fos_user.model.user.class%"]
    tags:
        - { name: form.type, alias: sonata_user_registration }
sonata.child.registration.form.type:
    class: Application'Sonata'UserBundle'Form'Type'ChildFormType
    arguments: [ "%fos_user.model.user.class%"]
    tags:
        - { name: form.type, alias: sonata_child_registration }
sonata.user.registration.form.handler.default:
    class: Application'Sonata'UserBundle'Form'Handler'RegistrationFormHandler
    scope: request
    public: false
    arguments: [@fos_user.registration.form, @request, @fos_user.user_manager, @fos_user.mailer, @fos_user.util.token_generator]

这是我的奏鸣曲用户配置(app/config/config.yml)

sonata_user:
    security_acl:           false
    manager_type: orm # Can be orm for mongodb
    table:
        user_group: "my_custom_user_group_association_table_name"
    impersonating:
        route:                page_slug
        parameters:           { path: / }
    class:                  # Entity Classes
        user:               Application'Sonata'UserBundle'Entity'User
        group:              Application'Sonata'UserBundle'Entity'Group
    admin:                  # Admin Classes
        user:
            class:          Sonata'UserBundle'Admin'Entity'UserAdmin
            controller:     SonataAdminBundle:CRUD
            translation:    SonataUserBundle
        group:
            class:          Sonata'UserBundle'Admin'Entity'GroupAdmin
            controller:     SonataAdminBundle:CRUD
            translation:    SonataUserBundle
    profile:  # Profile Form (firstname, lastname, etc ...)
        form:
            type:               sonata_user_profile
            handler:            sonata.user.profile.form.handler.default
            name:               sonata_user_profile_form
            validation_groups:  [Profile]
        register:
            # You may customize the registration forms over here
            form:
                type:                 sonata_user_registration
                handler:              sonata.user.registration.form.handler.default
                name:                 sonata_user_registration_form
                validation_groups:
                    # Defaults:
                    - Registration
                    - Default

我的树枝渲染:

{% block fos_user_content %}
    <br>
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <div class="well">
                <div class="panel-heading">
                    <h3>{{ 'title_user_registration'|trans({}, 'SonataUserBundle') }}</h3>
                </div>
                <div class="panel-body">
                    <form ng-app="userRegistrationApp" action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register form-horizontal">
                        <h4>{{ 'General'|trans({}, 'SonataUserBundle') }}</h4>
                        <hr>

                        <div class="form-group">
                            {{ form_label(form.username, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.username, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.email, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.email, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <br>
                        <h4>{{ 'form.label_plain_password'|trans({}, 'SonataUserBundle') }}</h4>
                        <hr>
                        <div class="form-group">
                            {{ form_label(form.plainPassword.first, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.plainPassword.first, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.plainPassword.second, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.plainPassword.second, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <br>
                        <h4>{{ 'Profile'|trans({}, 'SonataUserBundle') }}</h4>
                        <hr>
                        <div class="form-group">
                            {{ form_label(form.lastName, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.lastName, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.firstName, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.firstName, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.date_of_birth, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.date_of_birth, {'attr': {'class': '' }}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.gender, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.gender, {'attr': {'class': ''}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.phone, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.phone, {'attr': {'class': 'form-control bfh-phone', 'data-country':'sonata_user_registration_form_country'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.address, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.address, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.city, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.city, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.country, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.country, {'attr': {'class': 'form-control bfh-countries', ' data-country':'US'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.state, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.state, {'attr': {'class': 'form-control bfh-states', 'data-country':'sonata_user_registration_form_country'}}) }}
                            </div>
                        </div>
                        <div class="form-group">
                            {{ form_label(form.postalCode, null, {'label_attr': {'class': 'col-xs-4 control-label'}}) }}
                            <div class="col-xs-8">
                                {{ form_widget(form.postalCode, {'attr': {'class': 'form-control'}}) }}
                            </div>
                        </div>
                        <br>
                        {{ form_rest(form) }}

                        {#<a href="#Children" class="btn btn-link" ng-click="userRegistrationService.addEmptyChild()"><span class="glyphicon glyphicon-plus-sign"></span> {{ 'AddAChildren'|trans({}, 'SonataUserBundle') }}</a>#}

                        <div class="form-actions">
                            <button type="submit" class="btn btn-success pull-right">{{ 'registration.submit'|trans({}, 'FOSUserBundle') }}</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
{% endblock fos_user_content %}

我真的不知道为什么会出现错误:

array (size=1)
  0 => 
    object(Symfony'Component'Form'FormError)[1125]
      private 'message' => string 'Le jeton CSRF est invalide. Veuillez renvoyer le formulaire.' (length=60)
      protected 'messageTemplate' => string 'Le jeton CSRF est invalide. Veuillez renvoyer le formulaire.' (length=60)
      protected 'messageParameters' => 
        array (size=0)
          empty
      protected 'messagePluralization' => null

因为我的页面中有{{form_rest(form)}},并且存在令牌字段。。。

UPDATE我创建了一个github存储库,这样我的配置就可以被提取,这样你就可以自己看到问题了。https://github.com/ima-tech/testSonataUser

好吧,当我克隆你的github repo时,我能够通过调整你的服务来消除CSRF错误。

parameters:
#    osc_default.example.class: OSC'DefaultBundle'Example
services:
#    osc_default.example:
#        class: %osc_default.example.class%
#        arguments: [@service_id, "plain_value", %parameter%]
    sonata.user.registration.form.type:
        class: Application'Sonata'UserBundle'Form'Type'RegistrationFormType
        arguments: [ "%fos_user.model.user.class%"]
        tags:
            - { name: form.type, alias: sonata_user_registration }
    sonata.child.registration.form.type:
        class: Application'Sonata'UserBundle'Form'Type'ChildFormType
        arguments: [ "%fos_user.model.user.class%"]
        tags:
            - { name: form.type, alias: sonata_child_registration }
    sonata.user.registration.form.handler.default:
        class: Application'Sonata'UserBundle'Form'Handler'RegistrationFormHandler
        scope: request
        public: false
        arguments: [@sonata.user.registration.form, @request, @sonata.user.user_manager, @fos_user.mailer, @fos_user.util.token_generator]

您可以看到,在参数中的sonata.user.registration.form.handler.default:下,您需要设置@sonata.user.registration.form@sonata.user.user_manager,而不是@fos_user.registration.form@fos_user.user_manager