5

我正在尝试将位于我的 security.yml 中的 access_control 参数作为我的自定义服务中的一个数组。

就像获取 role_hierarchy 参数一样,我认为它可以使用以下代码:

$accessParameters = $this->container->getParameter('security.access_control');

不幸的是,情况并非如此。有人可以告诉如何获取参数吗?

4

2 回答 2

5

access_control无法从容器中获取参数。
这是因为此参数仅用于创建请求匹配器,这些匹配器将在稍后在AccessListener中注册为AccessMap,然后在没有将其注册到容器中的情况下留下。

你可以尝试一些 hacky 来让这些匹配器回来,让它们喜欢

$context  = $this->get("security.firewall.map.context.main")->getContext();
$listener = $context[0][5];
// Do reflection on "map" private member

但这是一种丑陋的解决方案。

我可以看到如何获取它们的另一种方法是再次解析安全文件

use Symfony\Component\Yaml\Yaml;

$file   = sprintf("%s/config/security.yml", $this->container->getParameter('kernel.root_dir'));
$parsed = Yaml::parse(file_get_contents($file));

$access = $parsed['security']['access_control'];

如果您想将此配置注册到服务中,您可以执行类似的操作

services.yml

services:
    acme.config_provider:
        class: Acme\FooBundle\ConfigProvider
        arguments:
            - "%kernel.root_dir%"
    acme.my_service:
        class: Acme\FooBundle\MyService
        arguments:
            - "@acme.config_provider"

Acme\FooBundle\ConfigProvider

use Symfony\Component\Yaml\Yaml;

class ConfigProvider
{
    protected $rootDir;

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

    public function getConfiguration()
    {
        $file = sprintf(
            "%s/config/security.yml",
            $this->rootDir
        );
        $parsed = Yaml::parse(file_get_contents($file));

        return $parsed['security']['access_control'];
    }
}

Acme\FooBundle\MyService

class MyService
{
    protected $provider;

    public function __construct(ConfigProvider $provider)
    {
        $this->provider = $provider;
    }

    public function doAction()
    {
        $access = $this->provider->getConfiguration();

        foreach ($access as $line) {
            // ...
        }
    }
}
于 2013-11-07T09:06:28.290 回答
0

死灵,但仍然相关。这是对上面 Touki 答案的改进,我们不重新解析 access_control 定义,而是使用已经配置的安全令牌、防火墙和访问映射来计算答案。

.../services.yml

...

My\Application\AuthenticationBundle\Security\AccessControlHelper:
    class: My\Application\AuthenticationBundle\Security\AccessControlHelper
    arguments:
        $securityContext: "@security.context"
        $firewall: '@security.firewall.map'
        $accessDecisionManager: '@security.access.decision_manager'
        $accessMap: '@security.access_map'

...

src/My/Application/AuthenticationBundle/Security/AccessControlHelper.php

declare(strict_types=1);

namespace My\Application\AuthenticationBundle\Security;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\Security\Http\Firewall\AccessListener;
use Symfony\Component\Security\Http\FirewallMapInterface;

class AccessControlHelper
{
    /**
     * @var SecurityContextInterface
     */
    protected $securityContext;

    /**
     * @var FirewallMapInterface
     */
    protected $firewallMap;

    /**
     * @var AccessDecisionManagerInterface
     */
    protected $accessDecisionManager;

    /**
     * @var AccessMapInterface
     */
    protected $accessMap;

    public function __construct(
        SecurityContextInterface $securityContext,
        FirewallMapInterface $firewallMap,
        AccessDecisionManagerInterface $accessDecisionManager,
        AccessMapInterface $accessMap
    )
    {
        $this->securityContext = $securityContext;
        $this->firewallMap = $firewallMap;
        $this->accessDecisionManager = $accessDecisionManager;
        $this->accessMap = $accessMap;
    }

    public function isRequestAccessible(Request $request): bool
    {
        $token = $this->securityContext->getToken();
        if (!$token || false == $token->isAuthenticated()) {
            return false;
        }

        list($listeners) = $this->firewallMap->getListeners($request);
        if ($listeners) {
            foreach ($listeners as $listener) {
                if ($listener instanceof AccessListener) {
                    /**
                     * Logic here is much inspired by the AccessListener->handle(...) method.
                     */
                    list($attributes) = $this->accessMap->getPatterns($request);

                    if (null === $attributes) {
                        continue;
                    }

                    return boolval($this->accessDecisionManager->decide($token, $attributes, $request));
                }
            }
        }
        return true;
    }

    public function isUriAccessible(string $uri)
    {
        return $this->isRequestAccessible(Request::create($uri));
    }
}

示例用法:

use My\Application\AuthenticationBundle\Security\AccessControlHelper;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;

$container = ...; // @var ContainerInterface

$accessControlHelper = $container->get(AccessControlHelper::class);
$accessControlHelper->isRequestAccessible(new Request("/foo"));
$accessControlHelper->isUriAccessible("/foo");
于 2019-08-30T10:38:00.513 回答