Symfony:在自定义捆绑包中定义角色层次结构

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

我有几个捆绑包,想要在其中定义一些角色和层次结构。该应用程序必须以某种方式将它们合并到一个层次结构中,我想强制以某种方式使用此层次结构安全捆绑包。

我尝试做的事情:

  1. 我使用编译器通道创建了
    CoreBundle
    类,并标记了所有具有角色元数据的类:
class CoreBundle extends AbstractBundle
{
    public function build(ContainerBuilder $container): void
    {
        parent::build($container);

        $container->addCompilerPass(new RoleHierarchyPass());
    }

    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
    {
        $container->import('../config/services.yaml');
        $builder->registerForAutoconfiguration(RoleHierarchyInterface::class)->addTag(RoleHierarchyInterface::class);
    }
}
  1. RoleHierarchyInterface
    很简单:
interface RoleHierarchyInterface
{
    public function getHierarchy(): array;
}

这是该接口实现的一个示例:

class CoreRoleHierarchy implements RoleHierarchyInterface
{
    public function getHierarchy(): array
    {
        return [
            'ROLE_DEVELOPER' => ["ROLE_USER"],
            'ROLE_ADMIN' => ["ROLE_USER"]
        ];
    }
}

我计划在未来添加更多的方法来描述角色(例如表单)。

  1. RoleHierarchyPass
    实施:
class RoleHierarchyPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if ($container->hasDefinition(RoleHierarchyAggregator::class)) {
            $taggedServices = $container->findTaggedServiceIds(RoleHierarchyInterface::class);
            $serviceReferences = [];
            foreach ($taggedServices as $serviceId => $tags) {
                $container->getDefinition($serviceId);
                $serviceReferences[] = new Reference($serviceId);
            }
            $definition = $container->findDefinition(RoleHierarchyAggregator::class);
            $definition->setArguments(['$roleHierarchyServices' => $serviceReferences]);
        }
    }
}
  1. RoleHierarchyAggregator
    实施:
readonly class RoleHierarchyAggregator
{
    public function __construct(private iterable $roleHierarchyServices = [])
    {
    }

    public function getMergedHierarchy(): array
    {
        $mergedHierarchy = [];
        foreach ($this->roleHierarchyServices as $roleHierarchyService) {
            if ($roleHierarchyService instanceof RoleHierarchyInterface) {
                $mergedHierarchy = array_merge_recursive($mergedHierarchy, $roleHierarchyService->getHierarchy());
            }
        }
        return $mergedHierarchy;
    }
}

我想更改

security.yaml
role_hierarchy,但我无法在
RoleHierarchyAggregator
服务中执行此操作。我尝试通过捆绑的
boot
方法来做到这一点:

public function boot()
{
    $container = $this->container;
    $roleHierarchyAggregator = $container->get(RoleHierarchyAggregator::class);
    dd($roleHierarchyAggregator);
}

但是它抛出以下异常:

容器编译时,“FooBar\CoreBundle\Security\RoleHierarchyAggregator”服务或别名已被删除或内联。您应该将其公开,或者直接停止使用容器并使用依赖项注入。

尝试将

CompilerPass
添加到
Kernel

class Kernel extends BaseKernel
{
    use MicroKernelTrait;

    protected function build(ContainerBuilder $container): void
    {
        parent::build($container);

        $container->addCompilerPass(new MergeRoleHierarchyPass());
    }
}
class MergeRoleHierarchyPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $taggedServices = $container->findTaggedServiceIds(RoleHierarchyInterface::class);
        foreach ($taggedServices as $serviceId => $tags) {
            dd($container->get($serviceId));
        }
        dd($container->getParameter('security.role_hierarchy.roles'));
    }
}

但这也会引发异常:

构建时不支持从父定义构建服务“FooBar\CoreBundle\Security\CoreRoleHierarchy”。

我不知道该怎么办。是否可以从不同的包中检索角色,合并它们然后传递给

security.yaml
?或者还有其他替代方案吗?

symfony symfony7
1个回答
0
投票

可以查看 PrepredExtension 来配置其他捆绑包中的安全捆绑包配置。例如,您的 CoreBundle 可以为安全包设置其角色:

$container->prependExtensionConfig('security', [
    'role_hierarchy' => [
        'ROLE_DEVELOPER' => ["ROLE_USER"],
        'ROLE_ADMIN'     => ["ROLE_USER"]
    ],
]);

参考:https://symfony.com/doc/current/bundles/prepend_extension.html

© www.soinside.com 2019 - 2024. All rights reserved.