简体   繁体   中英

Allow only ROLE_ADMIN to manage users in Sonata Admin

I have a Symfony 5.4 project using sonata-project/admin-bundle 4.9 and sonata-project/user-bundle 5.0.0-rc.1 and I want to let only the users with role ROLE_ADMIN to manage the users (CREATE/LIST/EDIT/DELETE), for other roles I want to hide the navbar menu entry and the dashboard entry for "Users".

In my config/packages/sonata_admin.yml I tried to specify a sonata.user.block.menu entry as found in some old questions but it seems that it does not exists anymore as the following error is thrown:

An exception has been thrown during the rendering of a template ("The block type "sonata.user.block.menu" does not exist").

As default I had only one admin_list block, I tried adding a sonata.block.service.rss and it is shown correctly in the dashboard but I can't find how to manage the Users block.

sonata_admin:
    title: 'Sonata Admin'
    dashboard:
        blocks:
            - { type: sonata.admin.block.admin_list, position: left }
            #- { type: sonata.user.block.menu, position: right, roles: [ROLE_ADMIN]}
            #- { type: sonata.block.service.rss, position: right, roles: [ROLE_ADMIN]}
    templates:
        layout: sonataLayout.html.twig


sonata_block:
    blocks:
        sonata.admin.block.admin_list:
            contexts: [admin]

Any hints? Explicative picture following.

Sonata 用户根据角色禁用

Note . "Disabled both based on Role". It`s not "just add/change 2 lines"

IMHO. "Basic" Sonata Admin`s configuration isn't too obvious. Therefore customize as much as possible -> to have more control.

I only could suggest U -> go this "right way" (surely,IMHO)

  1. Create/manage the admin-menu with a event listener. U may read/check good example there Using events to allow a menu to be extended and the official -> Sonata Admin -> KnpMenu

With such approach -> U can easy manage menu items by your Roles. + other advantages surely

  1. From the very beginning -> create the custom templates. If U follow Flex & /templates/admin is the folder for Sonata Admin:

     // config/packages/sonata_admin: sonata_admin.... templates: .... layout: '/admin/standard_layout.html.twig' knp_menu_template: '/admin/menu/knp_menu.html.twig' dashboard: 'admin...

2* Eg to extend the default layout. If your specific template do:

   {% extends '@SonataAdmin/standard_layout.html.twig' %}
   
   {% block sonata_nav %}
       ...  
      

After these steps -> much more easy to control views by your Roles

So, as per documentation I added an event listener for the Menu and I was able to remove the entry from the left panel like this

//src/EventListener/MenuBuilderListener.php
<?php
namespace App\EventListener;

use Sonata\AdminBundle\Event\ConfigureMenuEvent;
use Symfony\Component\Security\Core\Security;

final class MenuBuilderListener
{
    private $security;
    public function __construct( Security $security)
    {
        $this->security = $security;
    }

    public function manageMenuItems(ConfigureMenuEvent $event): void
    {
        $menu = $event->getMenu();
        $user = $this->security->getUser();
        if(!$user->hasRole("ROLE_ADMIN")){
            $menu->removeChild('sonata_user');
        }
    }
}

With the service registered here

//config/services.yaml
app.menu_listener:
    class: App\EventListener\MenuBuilderListener
    tags:
        - { name: kernel.event_listener, event: sonata.admin.event.configure.menu.sidebar, method: manageMenuItems }

Then I added a firewall entry to manage permissions

//config/packages/security.yaml
access_control:
    - { path: ^/admin/app/sonatauseruser/, role: [ROLE_ADMIN]}

Till now I was not able to remove the Users entry from the dashboard, I tried to extend the dashboard twig template but it seems that the Users entry is added somehow later.

{% extends '@SonataAdmin/Core/dashboard.html.twig' %}

{% block content %}
    {% set has_left = false %}
    {% dump(blocks.left) %} //this shows only the admin group and not the user group
    {% for block in blocks.left %}
        {% if not has_left and (block.roles|length == 0 or is_granted_affirmative(block.roles)) %}
            {% set has_left = true %}
        {% endif %}
    {% endfor %}
....
{{ sonata_block_render_event('sonata.admin.dashboard.top') }}
....
{{ sonata_block_render_event('sonata.admin.dashboard.bottom') }}

I also tried to bind both the render events.top and.bottom to a ConfigureEvent Listener but they are not fired (not sure if this is the right class of listener).

For now I found a sub optimal solution, I did an override of the userAdmin class like this

<?php
namespace App\Admin;

use Sonata\UserBundle\Admin\Model\UserAdmin as BaseType;

class UserAdmin extends BaseType
{
    protected function configureDashboardActions(array $actions): array
    {
        $actions = parent::configureDashboardActions($actions);
        unset($actions['list']);
        unset($actions['create']);
        return $actions;
    }
}

And registered it in

//config/packages/sonata_user.yaml
sonata_user:
    admin:
        user:
            class: App\Admin\UserAdmin
            controller: SonataAdminBundle:CRUD

So the "Users" dashboard element is shown without any action available.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM