Symfony2访问位于security.yml中的access_control参数

时间:2013-11-07 08:31:16

标签: php security symfony service access-control

我正在尝试将我的security.yml中的access_control参数作为我的自定义服务中的数组。 就像获取role_hierarchy参数一样,我认为它可以使用以下代码:

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

不幸的是情况并非如此 有人能说出如何获取参数吗?

2 个答案:

答案 0 :(得分:5)

无法从容器中获取access_control参数 这是因为此参数为only used以创建request matchers,稍后会在AccessMap中将其注册为AccessListener,然后将其保留而不将其注册到容器中。

你可以尝试一些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) {
            // ...
        }
    }
}

答案 1 :(得分: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 /我/应用程序/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");