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

Posted

技术标签:

【中文标题】在 FOSUserBundle 中管理用户/角色/组【英文标题】:Managing users/roles/groups in FOSUserBundle 【发布时间】:2014-11-09 12:51:55 【问题描述】:

我正在开发一个简单的 CRUD 来管理我正在工作的应用程序的用户/角色/组。为了管理用户,我使用FOSUserBundle。我想做的事情可以通过几种方式完成:

将角色分配给组,然后将用户分配给这些组 直接为用户分配角色

但我不知道怎么做。我知道FOSUser BaseUser 类已经有一个列roles 并且在FOSUser 的documentation 中解释了如何在用户和组之间建立ManyToMany 关系,但不谈论角色。想到的唯一想法是创建一个实体来管理角色以及一个用于相同目的的表单,如下所示:

角色实体

use Symfony\Component\Security\Core\Role\RoleInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="fos_role")
 * @ORM\Entity(repositoryClass="UserBundle\Entity\Repository\RoleRepository")
 * 
 * @see User
 * @see \UserBundle\Role\RoleHierarchy
 * 
 */
class Role implements RoleInterface

    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name="name", type="string", length=80, unique=true)
     */
    private $name;

    /**
     * @ORM\ManyToOne(targetEntity="Role", inversedBy="children")
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true)
     * @var Role[]
     */
    private $parent;

    /**
     * @ORM\OneToMany(targetEntity="Role", mappedBy="parent")
     * @var ArrayCollection|Role[]
     */
    private $children;

    /**
     * @ORM\ManyToMany(targetEntity="User", mappedBy="roles")
     */
    private $users;

    public function __construct($role = "")
    
        if (0 !== strlen($role)) 
            $this->name = strtoupper($role);
        

        $this->users = new ArrayCollection();
        $this->children = new ArrayCollection();
    

    /**
     * @see RoleInterface
     */
    public function getRole()
    
        return $this->name;
    

    public function getId()
    
        return $this->id;
    

    public function setId($id)
    
        $this->id = $id;
    

    public function getName()
    
        return $this->name;
    

    public function setName($name)
    
        $this->name = $name;
    

    public function getUsers()
    
        return $this->users;
    

    public function addUser($user, $addRoleToUser = true)
    
        $this->users->add($user);
        $addRoleToUser && $user->addRole($this, false);
    

    public function removeUser($user)
    
        $this->users->removeElement($user);
    

    public function getChildren()
    
        return $this->children;
    

    public function addChildren(Role $child, $setParentToChild = true)
    
        $this->children->add($child);
        $setParentToChild && $child->setParent($this, false);
    

    public function getDescendant(& $descendants = array())
    
        foreach ($this->children as $role) 
            $descendants[spl_object_hash($role)] = $role;
            $role->getDescendant($descendants);
        
        return $descendants;
    

    public function removeChildren(Role $children)
    
        $this->children->removeElement($children);
    

    public function getParent()
    
        return $this->parent;
    

    public function setParent(Role $parent, $addChildToParent = true)
    
        $addChildToParent && $parent->addChildren($this, false);
        $this->parent = $parent;
    

    public function __toString()
    
        if ($this->children->count()) 
            $childNameList = array();
            foreach ($this->children as $child) 
                $childNameList[] = $child->getName();
            
            return sprintf('%s [%s]', $this->name, implode(', ', $childNameList));
        
        return sprintf('%s', $this->name);
    

角色表单类型

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class RoleType extends AbstractType 

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder
                ->add('name')
                ->add('parent');
    

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    
        $resolver->setDefaults(array(
            'data_class' => 'Tanane\UserBundle\Entity\Role'
        ));
    

    /**
     * @return string
     */
    public function getName()
    
        return 'role';
        

如果是这样,添加到我的用户表单中的内容将如下所示

public function buildForm(FormBuilderInterface $builder, array $options)

    $builder
            ->add('username', 'text')
            ->add('email', 'email')
            ->add('enabled', null, array(
                'label' => 'Habilitado',
                'required' => false
            ))
            ->add('rolesCollection', 'entity', array(
                'class' => 'UserBundle:Role',
                'multiple' => true,
                'expanded' => true,
                'attr' => array('class' => 'single-line-checks')
            ))
            ->add('groups', 'entity', array(
                'class' => 'UserBundle:Group',
                'multiple' => true,
                'expanded' => true,
    ));

但我不知道这是否是处理角色的正确方法,因为在这种情况下将在我的数据库中创建一个名为 fos_roles 的新表,其中处理用户/角色之间的关系,但组之间的关系/角色远离它,那么这就是我有点迷茫的地方,需要更有经验的人的帮助,告诉我并提醒我是否走上正轨,这将使他们实现我在前两点中解释的内容。有什么建议或帮助吗?你是怎么处理的?

【问题讨论】:

【参考方案1】:

Symfony Roles

FOSUserBundle 处理角色的方式是将它们存储在您已经看到的roles 列中,采用如下序列化格式:a:1:i:0;s:10:"ROLE_ADMIN";。所以不需要任何其他表或实体^。

^ 这与组相反,组需要显式配置,由单独的表/实体表示,并且确实涉及将用户与数据库中的组相关联。组允许您定义任意的角色集合,然后可以将这些角色作为离散包提供给每个用户。

用户可以是任意数量的角色的成员。它们由以“ROLE_”开头的字符串标识,您可以开始使用新角色。

角色对您的应用程序意味着什么完全取决于您,但它们是一个相当高级的工具 - 用户要么处于特定角色中,要么不处于特定角色中。

您可以通过Symfony console 将人员置于角色中:

php app/console fos:user:promote testuser ROLE_ADMIN

或者在 PHP 中:

$user = $this->getUser();
$userManager = $container->get('fos_user.user_manager');
$user->addRole('ROLE_ADMIN');
$userManager->updateUser($user);

您可以在 PHP 中测试成员资格:

$user = $this->getUser();
if ($user->hasRole('ROLE_ADMIN'))

    //do something

或者使用Annotations:

/**
 * @Security("has_role('ROLE_ADMIN')")
 */
 public function adminAction()
 
     //...

/**
 * @Security("has_role('ROLE_ADMIN')")
 */
class AdminController

    //...

【讨论】:

【参考方案2】:

我通过覆盖注册控制器中的 confirmAction 添加了在注册期间向用户添加默认组的功能

我所做的是通过将父级定义为 FosUserBUndle 来覆盖项目 Bundle 中的注册控制器。

然后创建了一个函数confirmedAction,并在函数体中添加了这段代码

$repository = $em->getRepository('AdminAdminBundle:Group');
$group = $repository->findOneByName('staff');

$em = $this->getDoctrine()->getEntityManager();
$user = $this->getUser();
$user->addGroup($group);

$userManager = $this->get('fos_user.user_manager');

$userManager->updateUser($user);

if (!is_object($user) || !$user instanceof FOS\UserBundle\Model\UserInterface) 
    throw new AccessDeniedException('This user does not have access to this section.');


return $this->render('FOSUserBundle:Registration:confirmed.html.twig',
                      ['user' => $user]);

并且它通过组分配完美地保存在数据库中。

希望这会对有需要的人有所帮助,因为官方 fosuserbundle 文档中关于实施的信息很少。

【讨论】:

以上是关于在 FOSUserBundle 中管理用户/角色/组的主要内容,如果未能解决你的问题,请参考以下文章

使用 FosUserBundle symfony2 管理多个角色

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

Symfony2 FosUserBundle 角色 ROLE_ADMIN

将角色字段添加到 FOSUserBundle 组表单

FOSUserBundle (用户切换角色)

FOSUserBundle 组角色设置