Symfony2 get to the access_control parameters located in the security.yml

前端 未结 2 1212
北海茫月
北海茫月 2021-01-06 00:32

I\'m trying to get the access_control parameters which are located in my security.yml as an array in my custom service.

Just like with getting the role_hierarchy para

相关标签:
2条回答
  • 2021-01-06 01:18

    There's no way to get the access_control parameter from the container.
    This is because this parameter is only used to create request matchers which will be registered as AccessMap later given in the AccessListener, and then are left over without registering it into the container.

    You can try something hacky to get these matchers back by getting them like

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

    But this is kind of an ugly solution.

    Another way I can see on how to get them is to parse again the security file

    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'];
    

    If you want to register this configuration into a service, you can do something like

    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) {
                // ...
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-06 01:19

    Necro, but still relevant. This is an improvement on Touki's answer above, where we don't reparse the access_control definitions, but rather use the already configured security token, firewall and access map to work out the answer.

    .../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));
        }
    }
    

    Sample usage:

    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");
    
    0 讨论(0)
提交回复
热议问题