如何在数据库级别动态处理 Symfony2 中的角色|权限:对它们的 CRUD 操作

How to dynamic handle roles|permissions in Symfony2 at database level: CRUD operations over them

我在 Symfony 2.8 项目中工作,我对 users/groups/roles|权限有疑问。有几种方法可以处理用户和组,例如 SonataUser on top of SonataAdmin and lately EasyAdmin 但它们都缺乏 ROLE|权限管理,这正是我的疑问:处理它们的正确方法是什么?是的,我知道我需要将它们写在 security.yml 但我不知道我是否可以将它们存储在数据库(某处)中然后从那里读取。我对此进行了研究,发现了 ACL、选民等,但研究并没有让我头脑清醒,而是让我很困惑,所以我需要这里的人的一些推动。那么:

更新:改进问题

我想要的是 usersroles 以及 groupsroles 之间的 ManyToMany 关系。我认为 SonataUserBundle 处理这个问题是通过在 user table 中创建一个列 roles 并为每个用户分配很多角色,如果我是没错,但是如果我想创建尽可能多的角色而不将它们分配给用户,然后向用户甚至组添加许多角色怎么办?

你会怎么做?

您可以随时随地在 FOSUserBundle 中添加新角色。您最初无需将其添加到 security.yml 文件中。

为此,您可以这样做:

$user = new User();
$user->addRole('ROLE_NEWUSER'); //Role Name should begin with 'ROLE_'

或者在你的控制器中你可以获得当前或任何用户

$this->getUser();
$user->addRole('ROLE_NEWUSER'); //Role Name should begin with 'ROLE_'

这回答了你的第一部分和第二部分。

对于第三部分,角色可以用作权限。我之前已经实现了一个结构,在该结构中,我根据用户角色限制对页面的访问,同时也限制了他们可以根据他们的角色更改哪些数据。

UPDATE 我为此实现了一个 Event Listener,它将监听所有称为 onKernelRequest 的内核请求。我已经在 SQL 端完成了部分访问管理,因为我的角色也存储在 SQL 端,但可以在服务器端执行相同的操作。我的事件监听器看起来像这样:(这是我所拥有的精简版)

class TokenListener
{
    protected $em;
    protected $token_storage;
    protected $templating;
    protected $router;
    protected $resolver;
    public function __construct($em,TokenStorageInterface $token_storage, TwigEngine $templating, Router $router, ControllerResolver $resolver)
    {
        $this->em = $em;
        $this->token_storage = $token_storage;
        $this->templating = $templating;
        $this->router = $router;
        $this->resolver = $resolver;
    }


    public function onKernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        $route  = $request->attributes->get('_route');
        $routeArr = array('fos_js_routing_js', 'fos_user_security_login', '_wdt'); //These are excluded routes. These are always allowed. Required for login page
        if(!is_int(array_search($route, $routeArr)) && false)
        {
            $userRoles = $this->token_storage->getToken()->getUser()->getRoles();
            if(!in_array('ROLE_NEWUSER', $userRoles))
            {
                $event->setResponse(new RedirectResponse($this->router->generate('user_management_unauthorized_user', array())));
            }
        }
    }
}

我的services.yml看起来像这样

services:
    app.tokens.action_listener:
        class: EventListenerBundle\EventListener\TokenListener
        arguments:
            entityManager: "@doctrine.orm.entity_manager"
            token_storage: "@security.token_storage"
            templating: "@templating"
            router: "@router"
            resolver: "@controller_resolver"
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

UPDATE 要回答问题的更新部分,您可以做的是拥有另一个 roles 实体,您可以提前填充您想要的角色,然后与原来的Usertable是一对多的关系。然后,您可以使用 prePersist or preUpdate Doctrine Lifecycle Events 之类的东西来检查添加新角色时角色实体中是否已经存在。那应该可以准确地解决您的问题。不过,所有这些都需要进行一些调整。没有直接的方法可以做到这一点。

这取决于你想如何实现它。

一种方法:

实现UserProviderInterfaceloadByUsername(这是你加载角色和权限的地方)一个UserInterface(你的User)的实现。

然后实施 VoterInterface。将此注册为带有 security.voter 标记的服务,并在 security.yml 中将其指定为提供商。覆盖 vote 函数以评估您从 TokenInterface 加载的权限(可能还有角色),这是该函数的第一个参数。