安全
EasyAdmin 依赖于 Symfony Security 来处理所有与安全相关的事情。因此,在限制对后端某些部分的访问之前,您需要在 Symfony 应用程序中正确设置安全性
- 在您的应用程序中创建用户 并为其分配适当的权限(例如
ROLE_ADMIN
); - 定义一个防火墙,该防火墙覆盖后端的 URL。
限制对整个后端的访问
使用 access_control 选项,您可以告诉 Symfony 要求某些权限才能浏览与后端关联的 URL。这很简单,因为 仪表板路由共享一个公共前缀
1 2 3 4 5 6 7 8
# config/packages/security.yaml
security:
# ...
access_control:
# change '/admin' by the prefix used by your Dashboard URLs
- { path: ^/admin, roles: ROLE_ADMIN }
# ...
或者,您可以使用 #[IsGranted] 属性。但是,这可能很麻烦,因为您必须将其应用于所有仪表板控制器和所有 CRUD 控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// app/Controller/Admin/DashboardController.php
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
#[IsGranted('ROLE_ADMIN')]
class DashboardController extends AbstractDashboardController
{
// ...
}
// don't forget to also apply #[IsGranted('ROLE_ADMIN')] to all CRUD controllers
限制对某些 CRUD 控制器的访问
当使用多个 Dashboard 时,您可能需要限制每个仪表板可以访问哪些 CRUD 控制器。
假设在您的应用程序中,您有两个仪表板(员工使用的 DashboardController
和外部协作者使用的 GuestDashboardController
)。在访客仪表板中,您只想允许与您的博客相关的某些操作。
但是,当使用 漂亮的后台管理 URL 时,EasyAdmin 将为所有仪表板中的所有 CRUD 控制器生成路由。这意味着将会有不需要的路由,例如 admin_guest_invoice
、admin_guest_user_detail
等。限制每个仪表板可以通过哪些 CRUD 控制器访问的最佳方法是使用 #[AdminDashboard]
属性
1 2 3 4 5 6 7 8 9 10 11 12
// app/Controller/Admin/DashboardController.php
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
#[AdminDashboard(routePath: '/admin', routeName: 'admin', allowedControllers: [
BlogPostCrudController::class,
BlogCategoryCrudController::class,
])]
class DashboardController extends AbstractDashboardController
{
// ...
}
allowedControllers
选项定义了唯一可以通过 Symfony 路由在仪表板中使用的 CRUD 控制器。实际上,上述配置将使 EasyAdmin 仅生成路由 admin_guest_blog_post_*
和 admin_guest_blog_category_*
,跳过所有其他允许访问其他控制器的路由。
提示
您还可以定义相反的选项 (deniedControllers
) 以允许除该列表中包含的控制器之外的所有控制器。
限制对菜单项的访问
使用 setPermission()
方法定义用户必须具有的安全权限才能看到菜单项
1 2 3 4 5 6 7 8 9
public function configureMenuItems(): iterable
{
return [
// ...
MenuItem::linkToCrud('Blog Posts', null, BlogPost::class)
->setPermission('ROLE_EDITOR'),
];
}
注意
此权限仅显示/隐藏菜单项。与这些菜单项关联的操作仍然可执行,即使用户看不到菜单项。使用 操作权限 来限制对这些操作的访问。
如果您的需求更高级,请记住仪表板类是一个常规的 Symfony 控制器,因此您可以使用任何与安全相关的服务来评估复杂表达式。在这些情况下,使用替代菜单项定义更方便,而不必处理数组合并
1 2 3 4 5 6 7 8 9 10
public function configureMenuItems(): iterable
{
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
if ($this->isGranted('ROLE_EDITOR') && '...') {
yield MenuItem::linkToCrud('Blog Posts', null, BlogPost::class);
}
// ...
}
限制对操作的访问
使用 setPermission()
方法定义查看操作链接/按钮所需的安全权限
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
public function configureActions(Actions $actions): Actions
{
$viewInvoice = Action::new('invoice', 'View invoice', 'fa fa-file-invoice')
->linkToCrudAction('renderInvoice');
return $actions
// ...
->add(Crud::PAGE_DETAIL, $viewInvoice)
// use the 'setPermission()' method to set the permission of actions
// (the same permission is granted to the action on all pages)
->setPermission('invoice', 'ROLE_FINANCE')
// you can set permissions for built-in actions in the same way
->setPermission(Action::NEW, 'ROLE_ADMIN')
;
}
限制对字段的访问
有几种选项可以根据登录用户限制页面中显示的信息。首先,您可以使用 setPermission()
方法显示/隐藏整个字段
1 2 3 4 5 6 7 8 9 10 11 12
public function getFields(string $action): iterable
{
return [
IdField::new('id'),
TextField::new('price'),
IntegerField::new('stock'),
// users must have this permission/role to see this field
IntegerField::new('sales')->setPermission('ROLE_ADMIN'),
FloatField::new('commission')->setPermission('ROLE_FINANCE'),
// ...
];
}
您还可以使用 setEntityPermission()
方法限制用户可以在 index
和 detail
页面中查看的项目。此值作为调用 is_granted($permissions, $item)
函数的第一个参数传递,以确定当前用户是否可以查看给定的项目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
class ProductCrudController extends AbstractCrudController
{
// ...
public function configureCrud(Crud $crud): Crud
{
return $crud
->setEntityPermission('ROLE_ADMIN')
// ...
;
}
}
在 detail
页面中,如果用户没有权限,他们将看到适当的错误消息(您将在应用程序日志中看到详细的错误消息)。
在 index
页面中,为避免混淆和分页错误,如果用户没有权限查看某些项目,则将在列表底部显示一个空行,并显示一条消息,解释他们没有足够的权限查看某些项目

使用表达式限制访问
4.9.0
表达式支持在 EasyAdmin 4.9.0 中引入。
Symfony ExpressionLanguage 组件 允许使用简单表达式定义复杂的配置逻辑。在 EasyAdmin 中,所有 setPermission()
方法都允许传递不仅包含某些安全角色名称(例如 ROLE_ADMIN
)的字符串,还允许传递完整的 Expression
对象。
首先,使用 Composer 在您的项目中安装该组件
1
$ composer require symfony/expression-language
现在,您可以像这样将 Symfony Expression 对象传递给任何 setPermission()
方法
1 2 3 4
use Symfony\Component\ExpressionLanguage\Expression;
MenuItem::linkToCrud('Restricted menu-item', null, Example::class)
->setPermission(new Expression('"ROLE_DEVELOPER" in role_names and "ROLE_EXTERNAL" not in role_names'));
表达式支持定义更详细的权限,基于多个角色名称、用户属性或给定主题。表达式可以包含以下任何变量
user
- 当前用户对象role_names
- 当前用户的所有角色作为数组subject
或object
- 当前正在检查的主题token
- 身份验证令牌trust_resolver
- 身份验证信任解析器auth_checker
- 授权检查器服务的实例
自定义安全投票器
EasyAdmin 实现了 Symfony 安全投票器 来检查为操作、实体、菜单项等定义的权限。实际的安全权限在 EasyCorp
类中定义为常量(例如 Permission::EA_EXECUTE_ACTION
, Permission::EA_VIEW_MENU_ITEM
, 等)
如果您为后端定义了自定义安全投票器,请考虑更改应用程序使用的 访问决策策略。默认策略称为 affirmative
,只要有一个投票器授予访问权限,就授予访问权限(如果 EasyAdmin 投票器授予访问权限,您的自定义投票器将无法拒绝它)。
这就是为什么您应该将默认策略更改为 unanimous
,只有在没有投票器拒绝访问时才授予访问权限
1 2 3 4
# config/packages/security.yaml
security:
access_decision_manager:
strategy: unanimous