跳到内容

在安全访问控制中使用表达式

编辑此页

另请参阅

处理复杂授权规则的最佳方案是使用 Voter 系统

除了像 ROLE_ADMIN 这样的安全角色,isGranted() 方法和 #[IsGranted] 属性也接受 Expression 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/Controller/MyController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\Attribute\IsGranted;

class MyController extends AbstractController
{
    #[IsGranted(new Expression('is_granted("ROLE_ADMIN") or is_granted("ROLE_MANAGER")'))]
    public function show(): Response
    {
        // ...
    }

    #[IsGranted(new Expression(
        '"ROLE_ADMIN" in role_names or (is_authenticated() and user.isSuperAdmin())'
    ))]
    public function edit(): Response
    {
        // ...
    }
}

在此示例中,如果当前用户具有 ROLE_ADMIN 角色,或者如果当前用户对象的 isSuperAdmin() 方法返回 true,则将授予访问权限(注意:您的 User 对象可能没有 isSuperAdmin() 方法,该方法是为本示例虚构的)。

安全表达式必须使用任何有效的 表达式语言语法,并且可以使用 Symfony 创建的以下任何变量

user
表示当前用户的 UserInterface 实例,如果未经验证,则为 null
role_names
包含用户拥有的角色字符串表示形式的数组。此数组包含通过 角色继承体系 间接授予的任何角色,但不包括 IS_AUTHENTICATED_* 属性(请参阅下面的函数)。
object
作为第二个参数传递给 isGranted() 的对象(如果有)。
subject
它存储与 object 相同的值,因此它们是等效的。
token
令牌对象。
trust_resolver
AuthenticationTrustResolverInterface 对象:您可能更愿意使用下面的 is_*() 函数。

此外,您可以在表达式内部访问许多函数

is_authenticated()
如果用户通过 "remember-me" 验证或 "完全" 验证,则返回 true - 即,如果用户 "已登录",则返回 true。
is_remember_me()
类似于但不等同于 IS_AUTHENTICATED_REMEMBERED,请参见下文。
is_fully_authenticated()
等于检查用户是否具有 IS_AUTHENTICATED_FULLY 角色。
is_granted()
检查用户是否具有给定的权限。可以选择接受第二个参数,其中包含要检查权限的对象。它等效于使用安全服务的 isGranted() 方法

is_remember_me()is_fully_authenticated() 函数类似于将 IS_AUTHENTICATED_REMEMBEREDIS_AUTHENTICATED_FULLYisGranted() 函数一起使用 - 但它们相同。以下控制器代码段显示了差异

1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
// ...

public function index(AuthorizationCheckerInterface $authorizationChecker): Response
{
    $access1 = $authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED');

    $access2 = $authorizationChecker->isGranted(new Expression(
        'is_remember_me() or is_fully_authenticated()'
    ));
}

在此处,$access1$access2 将是相同的值。与 IS_AUTHENTICATED_REMEMBEREDIS_AUTHENTICATED_FULLY 的行为不同,is_remember_me() 函数在用户通过 "记住我" Cookie 验证时返回 true,而 is_fully_authenticated() 在用户在本会话期间实际登录时返回 true(即,完全登录)。

对于 #[IsGranted] 属性,subject 也可以是 Expression 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Controller/MyController.php
namespace App\Controller;

use App\Entity\Post;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\Attribute\IsGranted;

class MyController extends AbstractController
{
    #[IsGranted(
        attribute: new Expression('user === subject'),
        subject: new Expression('args["post"].getAuthor()'),
    )]
    public function index(Post $post): Response
    {
        // ...
    }
}

在本示例中,我们获取帖子的作者并将其用作 subject。如果 subject 与当前用户匹配,则将授予访问权限。

subject 也可以是一个数组,其中 key 可以用作表达式结果的别名

1
2
3
4
5
6
7
8
9
10
11
#[IsGranted(
    attribute: new Expression('user === subject["author"] and subject["post"].isPublished()'),
    subject: [
        'author' => new Expression('args["post"].getAuthor()'),
        'post',
    ],
)]
public function index(Post $post): Response
{
    // ...
}

在这里,如果作者与当前用户匹配,并且帖子的 isPublished() 方法返回 true,则将授予访问权限。

您也可以使用当前请求作为 subject

1
2
3
4
5
6
7
8
#[IsGranted(
    attribute: '...',
    subject: new Expression('request'),
)]
public function index(): Response
{
    // ...
}

在 subject 的表达式内部,您可以访问两个变量

request
表示当前请求的 Symfony Request 对象。
args
传递给控制器的控制器参数数组。
本作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
TOC
    版本