我正在尝试将位于我的 security.yml 中的 access_control 参数作为我的自定义服务中的一个数组。
就像获取 role_hierarchy 参数一样,我认为它可以使用以下代码:
$accessParameters = $this->container->getParameter('security.access_control');
不幸的是,情况并非如此。有人可以告诉如何获取参数吗?
我正在尝试将位于我的 security.yml 中的 access_control 参数作为我的自定义服务中的一个数组。
就像获取 role_hierarchy 参数一样,我认为它可以使用以下代码:
$accessParameters = $this->container->getParameter('security.access_control');
不幸的是,情况并非如此。有人可以告诉如何获取参数吗?
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) {
// ...
}
}
}
死灵,但仍然相关。这是对上面 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");