在使用 FOSUserBundle 进行用户注册期间添加默认角色

Posted

技术标签:

【中文标题】在使用 FOSUserBundle 进行用户注册期间添加默认角色【英文标题】:Add a default role during user registration with FOSUserBundle 【发布时间】:2013-04-06 07:05:57 【问题描述】:

版本:Symfony 2.2

当用户在我的网站上注册时,我正在尝试添加默认角色。我使用 FOSUserBundle,我看到当用户注册时,角色字段在数据库中为空。 我从这个巨大的捆绑包开始,它不是很容易理解。所以我阅读了所有文档,但我不知道该怎么做。

现在,我创建了一个事件来动态添加这个角色,但它不起作用(我没有错误,但我的数据库仍然是空的)我什至不知道这是不是这样做的好方法?

我的活动:

use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class AddDefaultRoleListener implements EventSubscriberInterface 

  private $container;

  public function __construct(Container $container)
  
    $this->container = $container;
  

  /**
   * @inheritDoc
   */
  public static function getSubscribedEvents()
  
    return array(
        FOSUserEvents::REGISTRATION_SUCCESS => 'onAddDefaultRoleSuccess',
    );
  

  public function onAddDefaultRoleSuccess(FormEvent $event)
  
    $doctrine = $this->container->get('doctrine');
    $em = $doctrine->getManager();

    $user = $event->getForm()->getData();
    $user->addRole('ROLE_USER');
    //$user->setRoles(array('ROLE_USER'));

    $em->persist($user);
  

如您所见,我创建了一个简单的事件来侦听 REGISTRATION_SUCCESS,但似乎没有任何效果。这是我第一次尝试使用事件和服务。所以如果有人有建议,我会接受的:)

【问题讨论】:

【参考方案1】:

您可以将事件订阅者添加到表单类并使用表单事件“formEvents::POST_SUBMIT”

<?php

//src/yourNS/UserBundle/Form/Type/RegistrationFormType.php

use Symfony\Component\Form\FormBuilderInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
use yourNS\UserBundle\Form\EventListener\AddRoleFieldSubscriber;

class RegistrationFormType extends BaseType
        
    public function buildForm(FormBuilderInterface $builder, array $options)
    
        parent::buildForm($builder, $options);

        // add your custom field
        $builder->add('firstName')
            ->add('lastName')
            ->add('address')
            //...
            //...
            ->add('phone');
        $builder->addEventSubscriber(new AddRoleFieldSubscriber());
    

    public function getName()
    
        return 'yourNS_user_registration';
    

现在添加角色字段的逻辑位于它自己的订阅者类中

<?php
//src/yourNS/UserBundle/Form/EventListener/AddRoleFieldSubscriber.php

namespace yourNS\UserBundle\Form\EventListener;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AddRoleFieldSubscriber implements EventSubscriberInterface

    public static function getSubscribedEvents()
    
        return array(FormEvents::POST_SUBMIT => 'setRole');
    

    public function setRole(FormEvent $event)
    
        $aRoles = array('ROLE_USER');

        /** @var $user \FOS\UserBundle\Model\UserInterface */
        $user = $event->getForm()->getData();
        $user->setRoles($aRoles);
    

【讨论】:

Entity/User.php 类的construct() 方法中使用$this-&gt;roles = ['ROLE_USER'] 工作,并且之前调用parent::__construct() 方法。【参考方案2】:
public function __construct()

    parent::__construct();
    $this->setRoles(["ROLE_WHATEVER"]);

【讨论】:

【参考方案3】:

我所做的是覆盖实体构造函数:

这是我的 Entity/User.php 的一部分

public function __construct()

    parent::__construct();
    // your own logic
    $this->roles = array('ROLE_USER');

这是懒惰的方式。如果您想要正确和更好的方法,请查看@RayOnAir answer

【讨论】:

这是“简单的方法”。 @rayonair 的答案是“正确的方式” @RodrigoLopezGuer​​ra 是的!但要保持简单;) 确定! :) 。但重要的是要标记差异。以“正确的方式”在重新注册完成后添加角色。在“简单的”中,每次执行 new User() 时,至少您始终牢记这一点可能会导致应用程序中的不当行为或最严重的安全漏洞【参考方案4】:

我认为@RayOnAir 解决方案是这样做的正确方法。但由于FOS default role handling,它不起作用

为了在数据库中保留默认角色,需要重写 User::setRoles() 方法(将其添加到您的 User 实体):

/**
 * Overriding Fos User class due to impossible to set default role ROLE_USER 
 * @see User at line 138
 * @link https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php#L138
 * @inheritdoc
 */
public function addRole($role)

    $role = strtoupper($role);

    if (!in_array($role, $this->roles, true)) 
        $this->roles[] = $role;
    

    return $this;

测试于:

Symfony 版本2.3.6, FOSUserBundle 2.0.x-dev

【讨论】:

@RayOnAir 和您的解决方案的结合使它适用于 Symfony2.4.0 和 github.com/FriendsOfSymfony/FOSUserBundle/commit/… 嗯,应该可以了,ROLE_USER 是 FOSUserBundle github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/… 的默认角色 为我工作,无需添加。 Symfony 2.8.0,FOSUserBundle 2.0.x-dev @godzillante:这取决于您为默认用户角色使用的值。使用"ROLE_USER" 无法工作,因为User addRole() 方法返回if ($role === static::ROLE_DEFAULT)(其中ROLE_DEFAULT"ROLE_USER")。【参考方案5】:

正如 FOSUserBundle (in the comment here linked) 的主要贡献者所指出的,推荐的方法是在 REGISTRATION_SUCCESS 事件上注册一个事件侦听器并使用 $event-&gt;getForm()-&gt;getData() 访问用户并对其进行修改。 按照这些准则,我创建了以下监听器(有效!):

<?php

// src/Acme/DemoBundle/EventListener/RegistrationListener.php

namespace Acme\DemoBundle\EventListener;

use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Listener responsible for adding the default user role at registration
 */
class RegistrationListener implements EventSubscriberInterface

    public static function getSubscribedEvents()
    
        return array(
            FOSUserEvents::REGISTRATION_SUCCESS => 'onRegistrationSuccess',
        );
    

    public function onRegistrationSuccess(FormEvent $event)
    
        $rolesArr = array('ROLE_USER');

        /** @var $user \FOS\UserBundle\Model\UserInterface */
        $user = $event->getForm()->getData();
        $user->setRoles($rolesArr);
    

另外,服务需要注册如下:

// src/Acme/DemoBundle/Resources/config/services.yml
services:
    demo_user.registration_listener:
        class: Acme\DemoBundle\EventListener\RegistrationListener
        arguments: []
        tags:
            -  name: kernel.event_subscriber 

请注意,在 User 类 __construct() 中添加默认角色可能会出现this other answer 中指出的一些问题。

【讨论】:

感谢您的回答和链接。您在 REGISTRATION_SUCCESS 事件中使用了与我相同的逻辑,但是当我上个月问这个问题时它对我不起作用(数据库中没有持久性)。但是使用 REGISTRATION_COMPLETED 事件就可以了。我会试试你的代码,再次感谢。 这是 FOS User Bundle V2 缺少的文档。 "//src/Acme/DemoBundle/Resources/config/services.xml" 你的例子不是YML文件吗?不是我在抱怨,我更喜欢 YML。但是可能会让一些人感到困惑。 这是执行此操作的首选方式。 也许你可以包含一个关于这将适用的版本的通知。 FOSUserEvents 不包含在 1.3.x 版本中。这是一个 v2 新增功能,仍在开发“dev-master”中。【参考方案6】:

好的,现在它正在使用它:

 public function onAddDefaultRoleSuccess(FilterUserResponseEvent $event)

    $doctrine = $this->container->get('doctrine');
    $em = $doctrine->getManager();

    $user = $event->getUser();
    $user->addRole('ROLE_BLOGGER');

    $em->persist($user);
    $em->flush();

我改变了我的听众并且知道使用 REGISTRATION_COMPLETED。如果有人有更好的主意,请不要犹豫:)

【讨论】:

如果用户无法访问或访问网站受限,我建议使用@alwar 写的内容,此任务的事件监听器是多余的 我同意这可以在构造函数中更好地完成,但事件侦听器示例对于以前使用过表单处理程序的人来说是一个很好的资源。

以上是关于在使用 FOSUserBundle 进行用户注册期间添加默认角色的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2:使用 FOSUserBundle 时如何在控制器内获取用户对象?

使用 FosUserBundle symfony2 管理多个角色

Symfony2 多 FosUserBundle

在 FOSUserBundle 中管理用户/角色/组

使用 FosUserBundle 创建管理员用户

在 FOSUserBundle 中通过 post 方法注册新用户时禁用 CSRF