我做过类似zis(将RoleHierarchy存储在数据库中)的事情,但我无法像ziIs那样在构造函数中加载完整的角色层次结构,因为我必须在事件中加载自定义原则过滤器。构造函数将在 之前调用,因此对我来说没有选择。kernel.requestkernel.request
因此,我检查了安全组件,发现调用自定义以根据用户角色进行检查:SymfonyVoterroleHierarchy
namespace Symfony\Component\Security\Core\Authorization\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
/**
 * RoleHierarchyVoter uses a RoleHierarchy to determine the roles granted to
 * the user before voting.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class RoleHierarchyVoter extends RoleVoter
{
    private $roleHierarchy;
    public function __construct(RoleHierarchyInterface $roleHierarchy, $prefix = 'ROLE_')
    {
        $this->roleHierarchy = $roleHierarchy;
        parent::__construct($prefix);
    }
    /**
     * {@inheritdoc}
     */
    protected function extractRoles(TokenInterface $token)
    {
        return $this->roleHierarchy->getReachableRoles($token->getRoles());
    }
}
getReachableRoles 方法返回用户可以成为的所有角色。例如:
           ROLE_ADMIN
         /             \
     ROLE_SUPERVISIOR  ROLE_BLA
        |               |
     ROLE_BRANCH       ROLE_BLA2
       |
     ROLE_EMP
or in Yaml:
ROLE_ADMIN:       [ ROLE_SUPERVISIOR, ROLE_BLA ]
ROLE_SUPERVISIOR: [ ROLE_BRANCH ]
ROLE_BLA:         [ ROLE_BLA2 ]
如果为用户分配了ROLE_SUPERVISOR角色,则方法将返回ROLE_SUPERVISOR、ROLE_BRANCH和ROLE_EMP(角色对象或类,实现角色接口)的角色
此外,如果在security.yaml
private function createRoleHierarchy($config, ContainerBuilder $container)
    {
        if (!isset($config['role_hierarchy'])) {
            $container->removeDefinition('security.access.role_hierarchy_voter');
            return;
        }
        $container->setParameter('security.role_hierarchy.roles', $config['role_hierarchy']);
        $container->removeDefinition('security.access.simple_role_voter');
    }
为了解决我的问题,我创建了自己的自定义投票者,并扩展了角色投票者类:
use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Acme\Foundation\UserBundle\Entity\Group;
use Doctrine\ORM\EntityManager;
class RoleHierarchyVoter extends RoleVoter {
    private $em;
    public function __construct(EntityManager $em, $prefix = 'ROLE_') {
        $this->em = $em;
        parent::__construct($prefix);
    }
    /**
     * {@inheritdoc}
     */
    protected function extractRoles(TokenInterface $token) {
        $group = $token->getUser()->getGroup();
        return $this->getReachableRoles($group);
    }
    public function getReachableRoles(Group $group, &$groups = array()) {
        $groups[] = $group;
        $children = $this->em->getRepository('AcmeFoundationUserBundle:Group')->createQueryBuilder('g')
                        ->where('g.parent = :group')
                        ->setParameter('group', $group->getId())
                        ->getQuery()
                        ->getResult();
        foreach($children as $child) {
            $this->getReachableRoles($child, $groups);
        }
        return $groups;
    }
}
一个注意:我的设置类似于zls的设置。我对角色的定义(在我的情况下,我称之为组):
Acme\Foundation\UserBundle\Entity\Group:
    type: entity
    table: sec_groups
    id: 
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        name:
            type: string
            length: 50
        role:
            type: string
            length: 20
    manyToOne:
        parent:
            targetEntity: Group
和用户定义:
Acme\Foundation\UserBundle\Entity\User:
    type: entity
    table: sec_users
    repositoryClass: Acme\Foundation\UserBundle\Entity\UserRepository
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        username:
            type: string
            length: 30
        salt:
            type: string
            length: 32
        password:
            type: string
            length: 100
        isActive:
            type: boolean
            column: is_active
    manyToOne:
        group:
            targetEntity: Group
            joinColumn:
                name: group_id
                referencedColumnName: id
                nullable: false
也许这对某人有帮助。