如何在Symfony2的security.yml中添加角色并管控SonataAdminBundle仪表盘子菜单显示
Hey there! Let's walk through how to add roles in Symfony2's security.yml and then control SonataAdminBundle submenu visibility based on those roles—super straightforward once you know the steps.
1. Adding Roles in Symfony2's security.yml
Symfony roles follow the ROLE_ naming convention, and you'll configure them in two main places: the role hierarchy (for role inheritance) and user providers (to assign roles to specific users).
Role Hierarchy
If you want roles to inherit permissions from other roles (e.g., ROLE_ADMIN gets all ROLE_USER permissions), define this in the role_hierarchy section. Add your custom role here too—let's say ROLE_SONATA_SUBMENU_ACCESS for your submenu control:
# app/config/security.yml security: role_hierarchy: ROLE_EDITOR: ROLE_USER ROLE_ADMIN: [ROLE_USER, ROLE_EDITOR] ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] # Your custom role for Sonata submenu access ROLE_SONATA_SUBMENU_ACCESS: ROLE_USER
Assign Roles to Users
You can assign roles directly to users via your user entity (if using a database provider) or in an in-memory provider for testing:
security: providers: in_memory: memory: users: john_doe: password: your_encoded_password roles: ['ROLE_USER', 'ROLE_SONATA_SUBMENU_ACCESS'] jane_smith: password: another_encoded_password roles: ['ROLE_ADMIN']
2. Controlling SonataAdminBundle Submenu Visibility
There are a few flexible ways to hide/show submenus based on roles—here are the most common and practical approaches:
Approach 1: Control Submenus Directly in Your Admin Class
This is the simplest method if you want granular control over a specific submenu. You'll use Symfony's AuthorizationCheckerInterface to check the user's role and conditionally add the submenu item.
First, inject the authorization checker into your Admin class:
// src/YourBundle/Admin/YourEntityAdmin.php namespace YourBundle\Admin; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Menu\MenuItemInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; class YourEntityAdmin extends AbstractAdmin { private $authorizationChecker; public function __construct($code, $class, $baseControllerName, AuthorizationCheckerInterface $authorizationChecker) { parent::__construct($code, $class, $baseControllerName); $this->authorizationChecker = $authorizationChecker; } // Control sidebar submenus protected function configureSideMenu(MenuItemInterface $menu, $action, \Sonata\AdminBundle\Admin\AdminInterface $childAdmin = null) { parent::configureSideMenu($menu, $action, $childAdmin); // Only show this submenu to users with ROLE_SONATA_SUBMENU_ACCESS if ($this->authorizationChecker->isGranted('ROLE_SONATA_SUBMENU_ACCESS')) { $menu->addChild('Your Restricted Submenu', [ 'uri' => $this->generateUrl('list'), 'attributes' => ['icon' => 'fa fa-list'] ]); } } // Or control top menu items (if needed) public function configureMenuItems(array $menuItems): array { $menuItems = parent::configureMenuItems($menuItems); if ($this->authorizationChecker->isGranted('ROLE_SONATA_SUBMENU_ACCESS')) { $menuItems[] = ['label' => 'Custom Top Menu', 'route' => 'your_custom_route']; } return $menuItems; } }
Approach 2: Restrict Entire Admin Sections to a Role
If you want to hide the entire Admin section (and its submenus) from users without the role, set the security directly in the Admin class:
class YourEntityAdmin extends AbstractAdmin { protected function configure() { parent::configure(); // Only users with ROLE_SONATA_SUBMENU_ACCESS can access this Admin section $this->setSecurity('ROLE_SONATA_SUBMENU_ACCESS'); } }
Approach 3: Global Menu Control with Event Listeners
For more global control (e.g., modifying multiple menus at once), use an event listener to hook into Sonata's menu-building process:
- Create the listener class:
// src/YourBundle/EventListener/SonataMenuListener.php namespace YourBundle\EventListener; use Sonata\AdminBundle\Event\ConfigureMenuEvent; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; class SonataMenuListener { private $authorizationChecker; public function __construct(AuthorizationCheckerInterface $authorizationChecker) { $this->authorizationChecker = $authorizationChecker; } public function configureSidebarMenu(ConfigureMenuEvent $event) { $menu = $event->getMenu(); // Loop through menu items and remove the restricted one if user lacks the role foreach ($menu->getChildren() as $child) { if ($child->getLabel() === 'Restricted Submenu') { if (!$this->authorizationChecker->isGranted('ROLE_SONATA_SUBMENU_ACCESS')) { $menu->removeChild($child); } } } } }
- Register the listener in your services:
# app/config/services.yml services: your_bundle.sonata_menu_listener: class: YourBundle\EventListener\SonataMenuListener arguments: ['@security.authorization_checker'] tags: - { name: kernel.event_listener, event: sonata.admin.event.configure.menu.sidebar, method: configureSidebarMenu }
Quick Recommendation
For most cases, Approach 1 is the best choice—it's simple, targeted, and keeps your menu logic right where it belongs (in the Admin class responsible for that section).
内容的提问来源于stack exchange,提问作者Oumayma Ben Ahmed

