用于迁移旧密码的自定义Symfony FOSUserBundle服务

时间:2016-02-16 21:20:18

标签: passwords fosuserbundle symfony

我正在尝试将自己的旧密码服务插入Symfony3,以便从旧数据库表中被动迁移用户。

遗留系统的密码具有在所有成员中使用的相同的硬编码$salt变量(因此,我的FOSUserBundle表目前对于要迁移的所有成员都具有空列的salt列)。

遗留方法使用:

sha1($salt1.$password.$salt2)

新方法是Symfony的FOSUserBundle标准bcrypt哈希。

我正在尝试实现它,以便当旧用户首次登录时,Symfony将尝试:

  1. 使用FOSUserBundle的标准bcrypt方法登录。
  2. 如果#1没有成功,那么尝试传统算法。
  3. 如果#2继续密码哈希,数据库表中的salt将更新为符合标准FOSUserBundle方法
  4. 我一直在阅读如何插入服务以使其正常工作,我认为我在下面的理论似乎是正确的 - 如果没有任何更正/指导将被赞赏,因为我无法测试它!

    但是,我不确定如何将它全部连接到Symfony,以便正常的FOSUserBundle进程在步骤1失败时执行步骤2和3

    services.yml:

    parameters:
        custom-password-encoder:
            class: AppBundle\Security\LegacyPasswordEncoder
    

    security.yml:

    security:
        encoders:
            #FOS\UserBundle\Model\UserInterface: bcrypt       Commented out to try the following alternative to give password migrating log in
             FOS\UserBundle\Model\UserInterface: { id: custom-password-encoder }
    

    BCryptPasswordEncoder(标准FOSUserBundle):

    class BCryptPasswordEncoder extends BasePasswordEncoder
    {
        /* .... */
    
        /**
         * {@inheritdoc}
         */
        public function encodePassword($raw, $salt)
        {
            if ($this->isPasswordTooLong($raw)) {
                throw new BadCredentialsException('Invalid password.');
            }
    
            $options = array('cost' => $this->cost);
    
            if ($salt) {
                // Ignore $salt, the auto-generated one is always the best
            }
    
            return password_hash($raw, PASSWORD_BCRYPT, $options);
        }
    
    
        /**
         * {@inheritdoc}
         */
        public function isPasswordValid($encoded, $raw, $salt)
        {
            return !$this->isPasswordTooLong($raw) && password_verify($raw, $encoded);
        }
    }
    

    LegacyPasswordEncoder:

    namespace AppBundle\Security;
    use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
    use Symfony\Component\Security\Core\Exception\BadCredentialsException;
    
    class LegacyPasswordEncoder extends BasePasswordEncoder
    {
        /**
         * {@inheritdoc}
         */
        public function encodePassword($raw,$salt)
        {
            if ($this->isPasswordTooLong($raw)) {
                throw new BadCredentialsException('Invalid password.');
            }
    
            list($salt1,$salt2) = explode(",",$salt);
            return sha1($salt1.$raw.$salt2);
        }
    
        /**
         * {@inheritdoc}
         */
        public function isPasswordValid($encoded, $raw, $salt)
        {
            list($salt1,$salt2) = explode(",",$salt);
            return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded,sha1($salt1.$raw.$salt2));
    
        }
    }
    

2 个答案:

答案 0 :(得分:1)

您的问题的解决方案是使用Symfony功能,允许根据用户动态更改密码哈希算法:https://symfony.com/doc/current/cookbook/security/named_encoders.html

这样,您可以将任何未迁移的用户标记为使用旧版算法。然后,在更新密码时,您将在保存用户之前重置正在使用的算法,以便使用新的更强算法对新密码进行哈希处理

答案 1 :(得分:0)

首先将您的用户类映射到所需的编码器:

{{1}}

这应该足以让你的编码器插上电源。

然后,您需要通过扩展BCryptPasswordEncoder并覆盖isPasswordValid方法来实际编写自定义编码器。当然,为它创建一个服务。有很多东西需要学习。

如何调用BcryptPasswordEncorder后跟LegacyPasswordEncoder?你没有。至少不是直接的。 Symfony没有链密码编码器。相反,编写自己的编码器并自己实现链接。

{{1}}

并确保在服务而非参数下定义编码器。还要确保将成本(默认值为13)作为构造函数参数传递。