我在Symfony2网站上使用FOSUserBundle。现在我正在开发一个API,允许通过REST api调用进行注册。
我已经覆盖了FOSUserBundle的RegistrationController:
ApiRegistrationController.php:
/**
* @Route("/user/", defaults = { "_format" = "json" }, requirements = { "_method" = "POST" })
*
*/
public function registerAction(Request $request)
{
[...]
$form = $formFactory->createForm(new ApiRegistrationFormType(), $user);
[...]
}
ApiRegistrationFormType.php:
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'BenMarten\UserBundle\Entity\User',
'intention' => 'registration',
'csrf_protection' => false
));
}
我收到有关错误的CSRF令牌的错误,所以我创建了自己的RegistrationFormType,以禁用CSRF - 但它被调用...
如何仅为api调用实现禁用CSRF令牌?
答案 0 :(得分:7)
因此,经过大量的时间摆弄,我得到了它的工作。我希望能节省一些时间。
我使用FOSRestBundle。
我在我的包中创建了自己的RestController:
<强> RestController.php 强>
namespace BenMarten\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\View\View;
/**
* Rest Controller
*/
class RestController extends Controller
{
/**
* Create a new resource
*
* @param Request $request
* @return View view instance
*
*/
public function postUserAction(Request $request)
{
/** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->container->get('fos_user.registration.form.factory');
/** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->container->get('fos_user.user_manager');
/** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
$dispatcher = $this->container->get('event_dispatcher');
$user = $userManager->createUser();
$user->setEnabled(true);
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $formFactory->createForm();
$form->setData($user);
$jsonData = json_decode($request->getContent(), true); // "true" to get an associative array
if ('POST' === $request->getMethod()) {
$form->bind($jsonData);
if ($form->isValid()) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
$userManager->updateUser($user);
$response = new Response("User created.", 201);
return $response;
}
}
$view = View::create($form, 400);
return $this->get('fos_rest.view_handler')->handle($view);
}
}
<强> RestRegistrationFormType.php 强>
namespace BenMarten\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\DependencyInjection\Container;
class RestRegistrationFormType extends AbstractType
{
protected $routeName;
private $class;
/**
* @param string $class The User class name
*/
public function __construct(Container $container, $class)
{
$request = $container->get('request');
$this->routeName = $request->get('_route');
$this->class = $class;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($this->routeName != "post_user")
{
$builder
->add('email', 'email', array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'))
->add('username', null, array('label' => 'form.username', 'translation_domain' => 'FOSUserBundle'))
->add('plainPassword', 'repeated', array(
'type' => 'password',
'options' => array('translation_domain' => 'FOSUserBundle'),
'first_options' => array('label' => 'form.password'),
'second_options' => array('label' => 'form.password_confirmation'),
'invalid_message' => 'fos_user.password.mismatch',
))
;
}
else
{
$builder
->add('email', 'email')
->add('username', null)
->add('plainPassword', 'password')
;
}
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
if ($this->routeName != "post_user")
{
$resolver->setDefaults(array(
'data_class' => $this->class,
'intention' => 'registration',
));
}
else
{
$resolver->setDefaults(array(
'data_class' => $this->class,
'intention' => 'registration',
'csrf_protection' => false
));
}
}
public function getName()
{
return 'fos_user_rest_registration';
}
}
将服务添加到Services.xml:
<service id="ben_marten.rest_registration.form.type" class="BenMarten\UserBundle\Form\RestRegistrationFormType">
<tag name="form.type" alias="fos_user_rest_registration" />
<argument type="service" id="service_container" />
<argument>BenMarten\UserBundle\Entity\User</argument>
</service>
在config.yml中:
registration:
form:
type: fos_user_rest_registration
所以基本上我告诉FOS用户包使用我自己的注册表单,根据路由我是否启用了csrf令牌......
答案 1 :(得分:2)
假设您同时使用FOSRestBundle
和FOSOAuthServerBundle
,那么您已经为已经实现的内容做了很多工作......我建议您在配置文件中添加2行:)< / p>
应用/ config.yml 强>
# we want to disable csrf roles for users with ROLE_API
fos_rest:
disable_csrf_role: ROLE_API
# We want to use scope to assign this role when the user requests the token
fos_oauth_server:
options:
supported_scopes: user api # https://goo.gl/iE9VoI
Et瞧!
当您使用范围api请求令牌时,您的用户会自动获得角色ROLE_API,并且CSRF约束消失了!
是的,它在doc:
中