Symfony2 - 重载注册表单导致 CSRF 错误(添加 github repo)
Posted
技术标签:
【中文标题】Symfony2 - 重载注册表单导致 CSRF 错误(添加 github repo)【英文标题】:Symfony2 - Overload registration form causes CSRF errors (added github repo) 【发布时间】:2014-05-21 22:43:48 【问题描述】:我目前正在重载 SonataUser 注册表单,以便在人们创建帐户时拥有自己的自定义表单。
我已经正确地重载了所有东西(处理程序、表单类型、控制器和树枝模板)。但是,当我发送表单时,我只取回数据并且没有创建新用户。因此,我进行了调查,发现当我回应这个时
var_dump($this->form->getErrors());
我收到一条错误消息,指出 CSRF 令牌无效。我正在使用Symfony 2.4.2
和sonata 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)
并且存在令牌字段...
更新我创建了一个 github 存储库,以便可以提取我的配置,以便您自己查看问题。 https://github.com/ima-tech/testSonataUser
【问题讨论】:
你能不能通过集成新的 symfony 和 sonata 设置来重现这个并将你的代码上传到 github。为我们解决您的问题会更容易 好吧,我终于有时间重做它,我有一个 github repo,这里是:github.com/ima-tech/testSonataUser 不幸的是问题仍然出现...... @user1191081 似乎即使在全新安装后问题仍然存在...... 【参考方案1】:好的,当我克隆你的 github 存储库时,我能够通过稍微调整你的服务来消除 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
【讨论】:
以上是关于Symfony2 - 重载注册表单导致 CSRF 错误(添加 github repo)的主要内容,如果未能解决你的问题,请参考以下文章
CSRF 和 RESTful API (symfony2, php)
在 ajax 提交时禁用 symfony 2 csrf 令牌保护