如何使用 Symfony Security 获得动态安全权限

How to get dynamic security privileges with Symfony Security

我需要在 Symfony 上的访问控制中添加自定义访问法,我试着解释一下。 我有一些客户的 Web 应用程序,当该客户拥有正确的插件时,我希望能够访问部分代码。这是我的客户:

namespace AppBundle\Entity;

class CustomerProfile{

private $id;

private $user;

private $plugins;
}

插件实体

namespace AppBundle\Entity;

class Plugin{

private $id;

private $name;

private $customerProfiles;
}

我对关系使用原则,所以我可以从客户那里得到他的插件。例如,我们有 2 个客户和 2 个插件:

AppBundle\Entity\CustomerProfile:
customer_1:
    user: '@user_1'
    plugins: ['@plugin_1','@plugin_2']
customer_2:
    user: '@user_2'
    plugins: ['@plugin_1']

AppBundle\Entity\Plugin:
plugin_1:
    name: 'plugin 1' 
plugin_2:
    name: 'plugin 2'

在我的项目中,所有关于客户的代码都在 /customer 命名空间下,Symfony 之类的,并且一切正常。

access_control:
    - { path: ^/customer, roles: ROLE_CUSTOMER }

但是,对于这个使用不同插件的客户,我会设置动态访问控制,但我不知道如何设置。我需要控制这样的东西:

access_control:
    - { path: ^/code_for_plugin_1, roles: ROLE_CUSTOMER_WHIT_PLUGIN_1}
    - { path: ^/code_for_plugin_2, roles: ROLE_CUSTOMER_WHIT_PLUGIN_2}

但我认为好的方法是设置 "sub role"(如果存在)为每个拥有插件的客户设置在该命名空间中访问的角色。

希望我说得够清楚,谢谢你的帮助。

我建议使用自定义选民而不是 access_control 和角色方法 我认为这对您的用例更灵活。您建议的解决方案需要 为每个插件生成一个角色 (ROLE_CUSTOMER_WHIT_PLUGIN_{X}),以防万一 动态添加插件是行不通的。

查看 Symfony 文档中的 How to Use Voters to Check User Permissions 文章了解更多详细信息。

你基本上需要实现一个用户投票器,它会检查登录的用户是否有访问权限 请求的资源。在您的情况下,它看起来类似于:

/src/YourBundle/Controller/YourController.php

<?php

...

class YourController extends Controller
{

    public function getFooAction($id)
    {
        $this->denyAccessUnlessGranted(YourVoter::VIEW_FOO);

        // ...method logic
    }

    public function getBarAction($id)
    {
        $this->denyAccessUnlessGranted(YourVoter::VIEW_BAR);

        // ...method logic
    }
}

/src/YourBundle/Security/YourVoter.php

<?php

...

class YourVoter extends AbstractVoter
{
    const VIEW_FOO = 'YOUR_VIEW_FOO';
    const VIEW_BAR = 'YOUR_VIEW_BAR';

    public function getVoterAttributes()
    {
        return [self::VIEW_FOO, self::VIEW_BAR,];
    }

    protected function supports($attribute, $subject)
    {
        ...
    }

    protected function voteOnAttribute($attribute, $item, TokenInterface $token)
    {
        $user = $token->getUser();
        if (!$user instanceof User) {
            return false;
        }

        switch ($attribute) {
            case self::VIEW_FOO:
                return $this->canViewFoo($user);
            case self::VIEW_BAR:
                return $this->canViewBar($user);
        }

        throw new \Exception(sprintf(
            'Invalid vote attribute "%s".',
            $attribute
        ));
    }

    private function canViewFoo(User $user)
    {
        return $user->getProfile()->hasRoleFooXYZ()
    }


    private function canViewBar(User $user)
    {
        return $user->getProfile()->hasRoleBarXYZ()
    }
}