Symfony 6.2 被授予多种角色

问题描述 投票:0回答:1

当我想向具有不同角色的用户授予访问权限时,我遇到了问题。 当我在表上下文中存储一些角色时,我为此创建了一个自定义投票者。

<?php

namespace App\Security\Voter;

use App\Constants\UserRoles;
use App\Entity\Team;
use App\Entity\User;
use App\Repository\UserTeamRepository;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

class TeamVoter extends Voter
{

    public function __construct(
        private UserTeamRepository $userTeamRepository,
    )
    {}

    /**
     * @inheritDoc
     */
    protected function supports(string $attribute, mixed $subject): bool
    {
        if (!in_array($attribute, UserRoles::TEAM_ROLES)) {
            return false;
        }

        return $subject instanceof Team;
    } 

    /**
     * @inheritDoc
     */
    protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();
        if (!$user instanceof User) {
            return false;
        }
        $team = $subject;

        if (in_array($attribute, UserRoles::TEAM_RELATED_ROLES)) {
            return $this->voteOnTeamRelatedAttribute($attribute, $user, $team);
        }

        return match($attribute) {
            UserRoles::ROLE_TEAM_ADMIN => $this->canEdit($user, $team),
            UserRoles::ROLE_TEAM_OWNER => $this->canDelete($user, $team),
            default => false,
        };
    }

    private function voteOnTeamRelatedAttribute(string $attribute, User $user, Team $team): bool
    {
        $userRoles = $this->userTeamRepository->getUserTeamRoles($user, $team->getExternalUuid());

        if (!$userRoles) {
            return false;
        }

        return match($attribute) {
            UserRoles::ROLE_TEAM_MEMBER_ADMIN => in_array(UserRoles::ROLE_TEAM_MEMBER_ADMIN, $userRoles),
            UserRoles::ROLE_TEAM_MEMBER => in_array(UserRoles::ROLE_TEAM_MEMBER, $userRoles),
            default => false,
        };
    }

    private function canEdit(User $user, Team $team): bool
    {
        if ($this->canDelete($user, $team)) {
            return true;
        }

        return in_array(UserRoles::ROLE_TEAM_ADMIN, $user->getRoles());
    }

    public function canDelete(User $user, Team $team): bool
    {
        return $team->getOwner() === $user || $team->getCreator() === $user;
    }
}

现在我希望具有角色 ROLE_TEAM_ADMIN 的用户或具有角色 ROLE_TEAM_MEMBER_ADMIN 的用户可以访问该方法(注意: ROLE_TEAM_ADMIN 更多的是编辑所有团队的全局角色,而 ROLE_TEAM_MEMBER_ADMIN 更专注于单个团队,因此自定义投票者检查mm表的内容)

这是我的控制器中受保护的方法:

    #[Route('/rest/team/{externalUuid}/member/add', name: 'add_team_member', methods: ["PUT"])]
    #[IsGranted(UserRoles::ROLE_TEAM_ADMIN, subject: 'team'), IsGranted(UserRoles::ROLE_TEAM_MEMBER_ADMIN, subject: 'team')]
    public function addTeamMember(Request $request, Team $team): JsonResponse
    {
        $request = $this->transformJsonBody($request);
    ...

文档表示可以配置授予决策策略,但其默认值设置为“肯定”,这意味着如果参与授予的其中一位投票者表示可以,则授予访问权限。

我的问题是,这并没有按预期工作,而是遵循“一致”决策模式。我已经浏览过 stackoverflow 上的这个主题,有些人建议使用表达式,但这些答案已经过时了,因为它适用于 symfony 5 和已弃用的 Sensio 安全包。

调试后,我注意到 Symfony\Component\Security\Core\Authorization\AccessDecisionManager 类收集结果(在collectResults方法中),查找投票者并在此基础上构建其决策,但属性数组始终带有一个属性只是。

所以我猜我的注释是以错误的方式定义的,但我在文档中找不到任何有关如何处理决策管理器的相关示例,显然设置一个又一个注释是不够的。

有人有好的方法来处理这个问题吗?

php roles symfony6
1个回答
0
投票

我相信使用多个

IsGranted()
调用与使用表达式
$this->isGranted() && $this->isGranted()
相同。

要使用

OR
逻辑运算符而不是
AND
,请查看 表达式语法。您可以在基础
#[IsGranted(string)]
的能力之上进行非常复杂的检查:

use Symfony\Component\ExpressionLanguage\Expression;

// ...

    #[Route('/rest/team/{externalUuid}/member/add', name: 'add_team_member', methods: ["PUT"])]
    #[IsGranted(
        new Expression(
            'is_granted("' . UserRoles::ROLE_TEAM_ADMIN . '", subject) or ' .
            'is_granted("' . UserRoles::ROLE_TEAM_MEMBER_ADMIN . '", subject)'
        ),
        subject: 'team'
    ]
    public function addTeamMember(Request $request, Team $team): JsonResponse
    {
        $request = $this->transformJsonBody($request);
        // ...
    }
© www.soinside.com 2019 - 2024. All rights reserved.