Symfony2:从另一个选民那里呼叫选民

时间:2016-10-14 15:35:19

标签: symfony symfony2-voter

我正在使用Voters来限制对REST API中实体的访问。

第1步

考虑一下这个限制用户访问博客帖子的选民:

class BlogPostVoter extends Voter
{
    public function __construct(AccessDecisionManagerInterface $decisionManager)
    {
        $this->decisionManager = $decisionManager;
    }

    /**
     * Determines if the attribute and subject are supported by this voter.
     *
     * @param string $attribute An attribute
     * @param int $subject The subject to secure, e.g. an object the user wants to access or any other PHP type
     *
     * @return bool True if the attribute and subject are supported, false otherwise
     */
    protected function supports($attribute, $subject)
    {
        if (!in_array($attribute, $this->allowedAttributes)) {
            return false;
        }
        if (!$subject instanceof BlogPost) {
            return false;
        }

        return true;
    }

    /**
     * Perform a single access check operation on a given attribute, subject and token.
     *
     * @param string $attribute
     * @param mixed $subject
     * @param TokenInterface $token
     * @return bool
     * @throws \Exception
     */
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        return $this->canUserAccess($attribute, $subject, $token);
    }

    public function canUserAccess($attribute, $subject, TokenInterface $token) {
        if ($this->decisionManager->decide($token, array('ROLE_SUPPORT', 'ROLE_ADMIN'))) {
            return true;
        } 

        //other logic here omitted ...

        return false;
    }
}

您可以看到有一个公共函数canUserAccess来确定是否允许用户查看BlogPost。这一切都很好。

第2步

现在我有另一个选民来检查其他内容,但也需要检查BlogPosts的这个相同的逻辑。我的想法是:

  • 添加新选民
  • 执行其他一些检查
  • 但随后也会执行此BlogPost检查

所以我想我会将BlogPostVoter注入我的其他选民:

class SomeOtherVoter extends Voter
{
    public function __construct(BlogPostVoter $blogPostVoter)
    {
        $this->decisionManager = $decisionManager;
    }

    ...

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        //other logic

        if ($this->blogPostVoter->canUserAccess($attribute, $subject, $token))    {
           return true;
        }

        return false;
    }
}

问题

当我这样做时,我使用setter和构造函数注入得到以下错误:

检测到服务的循环引用" security.access.decision_manager",路径:" security.access.decision_manager"

我不知道security.access.decision_manager应该依赖于选民的实施。所以我没有看到循环引用的位置。

我还有另一种方式可以从VoterB呼叫VoterA吗?

1 个答案:

答案 0 :(得分:1)

要引用VoterOne中的VoterTwo,您可以将AuthorizationCheckerInterface注入VoterTwo中,然后调用->isGranted('ONE')。其中ONE是VoterOne的受支持属性。

赞:

class VoterTwo extends Voter
{
    private $authorizationChecker;

    public function __construct(AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->authorizationChecker = $authorizationChecker;
    }

    protected function supports($attribute, $subject)
    {
        return in_array($attribute, ['TWO']);
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        return $this->authorizationChecker->isGranted('ONE', $subject);
    }
}

在此示例中,VoterTwo只是将请求重定向到VoterOne(或支持属性ONE的投票者)。然后可以通过附加条件来扩展它。