Php 自定义密码编码器symfony 5

Php 自定义密码编码器symfony 5,php,symfony,Php,Symfony,我正在尝试集成我的旧数据库密码验证器,为此我配置了自定义编码密码: 我使用的是symfony5.1和php7.4 这是我的安全 security: encoders: App\Entity\User: algorithm: auto #para oracle puse auto app_encoder: id: 'App\Security\Encoder\MyCustomPasswo

我正在尝试集成我的旧数据库密码验证器,为此我配置了自定义编码密码:

我使用的是symfony5.1和php7.4

这是我的安全

security:
    encoders:
        App\Entity\User:
            algorithm: auto 
            #para oracle puse auto
        app_encoder:
            id: 'App\Security\Encoder\MyCustomPasswordEncoder'
            #para oracle
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            lazy: true
            provider: app_user_provider
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: app_logout
                #target: app_logout
            remember_me:
                secret:   '%kernel.secret%'
                lifetime: 2592000 # 30 days in seconds

            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#firewalls-authentication

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        #- { path: ^/admin, roles: ROLE_ADMIN }
        # - { path: ^/profile, roles: ROLE_USER }
这是我的密码自定义编码器src/Security/encoder/MyCustomPasswordEncoder.php

<?php
namespace App\Security\Encoder;

use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class MyCustomPasswordEncoder implements UserPasswordEncoderInterface
{

    /**
     * {@inheritdoc}
     */
    public function encodePassword(UserInterface $user, string $plainPassword)
    {
        $encoder = $this->encoderFactory->getEncoder($user);

        return $encoder->encodePassword($plainPassword, $user->getSalt());
    }

    /**
     * {@inheritdoc}
     */
    public function isPasswordValid(UserInterface $user, string $raw)
    {
        if (null === $user->getPassword()) {
            return false;
        }

        die('Esta usando la mia');

        $encoder = $this->encoderFactory->getEncoder($user);

        return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt());
    }

    /**
     * {@inheritdoc}
     */
    public function needsRehash(UserInterface $user): bool
    {
    if (null === $user->getPassword()) {
            return false;
        }

        $encoder = $this->encoderFactory->getEncoder($user);

        return $encoder->needsRehash($user->getPassword());
    }
}

事情可能会变得混乱,因为涉及到两个接口:PasswordEncoderface和UserPasswordEncoderface。有一种倾向是希望创建自定义UserPasswordEncoderInterface,因为您正在编码用户密码。但事实上,UserPasswordEncoder对象基本上只是底层PasswordEncoder的包装器

因此,您需要在PasswordEncoder对象中实现旧数据库密码验证器:

namespace App\Security;

use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;

class MyPasswordEncoder implements PasswordEncoderInterface
{
    public function encodePassword(string $raw, ?string $salt)
    {
        return 'ENCODED' . $raw;
    }
    public function isPasswordValid(string $encoded, string $raw, ?string $salt)
    {
        return true;
    }
    public function needsRehash(string $encoded): bool
    {
        return false;
    }
}
接下来,您需要告诉Symfony为给定类型的用户使用自定义编码器:

# config/packages/security.yaml
security:
    encoders:
        App\Entity\User:
            id: App\Security\MyPasswordEncoder
此时,您可以确认编码器正在与以下设备一起使用:

$ bin/console security:encode-password xxx
Encoder used       App\Security\MyPasswordEncoder            
Encoded password   ENCODEDxxx   
这应该足以让你行动起来。但冒着增加更多混淆的风险,这里有一个小测试命令,它试图显示UserPasswordEncoderInterface、PasswordEncoderInterface和EncoderFactoryInterface之间的关系,EncoderFactoryInterface基本上根据security.yaml映射为给定用户选择正确的编码器:

class UserCommand extends Command
{
    protected static $defaultName = 'app:user';

    private $encoderFactory;
    private $userPasswordEncoder;

    public function __construct(EncoderFactoryInterface $encoderFactory, UserPasswordEncoderInterface $userPasswordEncoder)
    {
        parent::__construct();
        $this->encoderFactory = $encoderFactory;
        $this->userPasswordEncoder = $userPasswordEncoder;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $encoder = $this->encoderFactory->getEncoder(User::class);
        echo get_class($encoder) . "\n";

        $user = new User();
        $encoded = $this->userPasswordEncoder->encodePassword($user,'zzz');
        echo $encoded . "\n";

        return Command::SUCCESS;
    }
}
还想指出问题中的链接指向使用命名编码器。命名编码器允许将多个编码器映射到单个实体类,然后允许实体根据某些属性选择编码器。例如,管理员用户可能使用与普通用户不同的编码器。命名编码器不适用于此用例


不过,您可能希望了解如何自动执行。配置后,用户可以使用旧编码器登录,然后自动更新为新编码器。

您到底想实现什么?为所有用户使用您自己的编码器还是仅为其中的一部分?您提供的链接谈到了命名编码器,但我没有看到任何证据表明您正在这样做。您需要了解UserPasswordEncoderInterface和PasswordEncoderInterface之间的区别。您的自定义编码器将实现PasswordEncoderface。将编码器映射到安全文件中的用户。我可以给你一个完整的例子,但不清楚你到底想做什么。我需要为所有用户使用我自己的编码器。我不理解UserPasswordEncoderInterface和PasswordEncoderInterface之间的区别,我找不到文档。如果我可以使用自己的编码器,我将尝试添加对数据库函数的调用,以验证isValidPassword中的密码method@RaulCejas这一切都变得有点混乱。有些交互不适合stackoverflow。考虑在SeffReDeDIT上打开一个帖子,在这里只是引用这个问题。我也监视它。我在下面的回答确实表明,当一切都连接好时,注入UserPasswordEncoderInterface会按预期工作。“bin/console debug:container UserPasswordEncoderInterface”应该会生成默认的“Symfony\Component\Security\Core\Encoder\UserPasswordEncoder”类。我已经为此忙了3天了。感谢您为我们这些尝试使用遗留系统的人澄清这一点。
class UserCommand extends Command
{
    protected static $defaultName = 'app:user';

    private $encoderFactory;
    private $userPasswordEncoder;

    public function __construct(EncoderFactoryInterface $encoderFactory, UserPasswordEncoderInterface $userPasswordEncoder)
    {
        parent::__construct();
        $this->encoderFactory = $encoderFactory;
        $this->userPasswordEncoder = $userPasswordEncoder;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $encoder = $this->encoderFactory->getEncoder(User::class);
        echo get_class($encoder) . "\n";

        $user = new User();
        $encoded = $this->userPasswordEncoder->encodePassword($user,'zzz');
        echo $encoded . "\n";

        return Command::SUCCESS;
    }
}