首页 > 解决方案 > 更改内存提供程序的默认用户对象

问题描述

我只是想更改User内存提供程序的默认对象。默认User对象是Symfony\Component\Security\Core\User\User. 但是这个对象不能满足我的要求,所以我复制了那个对象并为我的要求添加了一些属性,然后将它命名为InMemoryUser并使用它,如下所示:

encoders:
    App\Component\Security\Core\User\InMemoryUser: plaintext

然后在尝试运行该应用程序时出现以下错误。

No encoder has been configured for account "App\Component\Security\Core\User\InMemoryUser"

在调查了大约半小时后,我看到了这个问题。Symfony 默认调用Symfony\Component\Security\Core\User\InMemoryUserProvider并使用Symfony\Component\Security\Core\User\User对象在__construct方法中创建内存用户。

然后我尝试InMemoryUserProvider如下覆盖默认值。

services:

    App\Component\Security\Core\User\CustomInMemoryUserProvider:
        decorates: security.user.provider.concrete.api_user_provider
        arguments:
            $users: []  # this should be contains in-memory users defined in the security.yaml but i dont know how to do that.

这工作正常,除了一个小问题,不会$usersInMemoryUserProvider. 通常,$users包含定义在内存中的用户列表security.yaml

现在,我如何$users为我注入,CustomInMemoryUserProvider这是更改User对象的好习惯InMemoryProvider吗?

提前感谢您的回答。

顺便说一句,我正在使用symfony 5.1

标签: phpsymfonydependency-injectionsymfony5

解决方案


我从来没有完全破解正确装饰其构造函数由 DI 扩展动态注入的服务的奥秘。

但是,在这种情况下,您真正​​需要做的就是更改内存提供程序的类,这可以在内核中的编译器传递中完成:

# src\Kernel.php
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use App\User\InMemoryUserProvider;
class Kernel extends BaseKernel implements CompilerPassInterface
...
    public function process(ContainerBuilder $container)
    {
        $id = 'security.user.provider.in_memory';
        $container->getDefinition($id)->setClass(InMemoryUserProvider::class);
    }

在测试这个时,我最初尝试扩展内存提供程序中的现有核心,但它使用了一个不能被覆盖的私有方法。所以我只是重新实现了完整的界面

namespace App\User;
class InMemoryUserProvider implements UserProviderInterface
{
    public function __construct(array $users)
    {
        dump($users); // Confirms get the users from security.yaml
    }
    public function loadUserByUsername(string $username)
    {
        // TODO: Implement loadUserByUsername() method.
        echo "Get User {$username}\n";
    }

确认它已按预期连接:

bin/console debug:container | grep UserProv                                               
  App\User\InMemoryUserProvider = App\User\InMemoryUserProvider                                                                   
  Symfony\Component\Security\Core\User\UserProviderInterface = alias for "security.user.provider.concrete.users_in_memory"                                                                                                                    
  security.user.provider.concrete.users_in_memory = App\User\InMemoryUserProvider                                                                   
  security.user.provider.in_memory = App\User\InMemoryUserProvider                                                                                  

并发出一个命令来验证它是否按预期工作:

class UserProviderCommand extends Command
{
    protected static $defaultName = 'user:provider';

    private $userProvider;

    public function __construct(UserProviderInterface $userProvider)
    {
        parent::__construct();
        $this->userProvider = $userProvider;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        echo "User Provider: " . get_class($this->userProvider) . "\n";
        $this->userProvider->loadUserByUsername('xxx');
        return 0;
    }
}

推荐阅读