如何在Symfony项目中覆盖Bundle的security配置
Bundle 侧配置
我有一个包含预定义security.yaml配置的Symfony Bundle,配置内容如下:
security: password_hashers: Bundle\Entity\User: algorithm: bcrypt # ... access_control: - { path: ^/api/public, roles: PUBLIC_ACCESS } - { path: ^/admin/, role: ROLE_ADMIN }
通过实现PrependExtensionInterface预加载配置:
class BundleExtension extends Extension implements PrependExtensionInterface { public function prepend(ContainerBuilder $container): void { $yamlParser = new Parser(); $securityConfig = $yamlParser->parse(file_get_contents(__DIR__ . '/../Resources/config/security.yml')); $container->prependExtensionConfig('security', $securityConfig['security']); } }
项目侧需求与尝试
我想在项目中修改或追加access_control下的路径,于是在Kernel.php中添加了编译器通道:
class Kernel extends BaseKernel { use MicroKernelTrait; protected function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass(new SecurityConfigCompilerPass()); } }
并编写了SecurityConfigCompilerPass:
class SecurityConfigCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container): void { $securityConfigs = $container->getExtensionConfig('security'); foreach ($securityConfigs as $securityConfig) { if (array_key_exists('access_control', $securityConfig)) { $newConfig = $securityConfig; array_push($newConfig['access_control'], [ "path" => "^/", "role" => "ROLE_ADMIN", ]); } } $securityExtension = $container->getExtension('security'); $securityExtension->load($newConfig, $container); } }
错误信息
执行后出现以下错误:
Unrecognized option "Bundle\Entity\User" under "security". Available options are "access_control", "access_decision_manager", "access_denied_url", "enable_authenticator_manager", "erase_credentials", "firewalls", "hide_user_not_found", "password_hashers", "providers", "role_hierarchy", "session_fixation_strategy".
不清楚为何无法识别Bundle\Entity\User命名空间,请问有没有更好的修改access_control路径的方法?
错误原因
你直接调用$securityExtension->load($newConfig, $container)会重新加载整个security配置,但$newConfig中的Bundle\Entity\User是嵌套在password_hashers下的实体配置,你的代码处理时破坏了原有配置层级,导致Symfony把实体类名当成了security的顶级选项,从而触发错误。
正确修改方式
方式1:直接在项目security.yaml中追加(推荐)
Symfony配置遵循项目配置优先合并规则,你只需在项目根目录的config/packages/security.yaml中直接添加或修改access_control规则即可,无需额外编写代码:
# config/packages/security.yaml security: access_control: # 新规则会和Bundle中的规则自动合并 - { path: ^/, role: ROLE_ADMIN }
方式2:通过编译器通道正确修改配置
如果必须用编译器通道,需要先处理并保留原有配置结构,再追加规则:
class SecurityConfigCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container): void { // 获取并处理所有已加载的security配置,确保结构正确 $securityExtension = $container->getExtension('security'); $configs = $container->getExtensionConfig('security'); $processedConfig = $securityExtension->processConfiguration( new SecurityConfiguration(), $configs ); // 追加新的access_control规则 $processedConfig['access_control'][] = [ 'path' => '^/', 'role' => 'ROLE_ADMIN' ]; // 清空原有配置,重新注入处理后的完整配置 $securityExtension->removeConfigs(); $container->prependExtensionConfig('security', $processedConfig); } }
内容的提问来源于stack exchange,提问作者tobias47n9e

