【问题标题】:Custom Symfony FOSUserBundle service for migrating legacy passwords用于迁移旧密码的自定义 Symfony FOSUserBundle 服务
【发布时间】:2016-05-28 08:39:44
【问题描述】:

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

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

遗留方法使用:

sha1($salt1.$password.$salt2)

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

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

  1. 使用 FOSUserBundle 的标准 bcrypt 方法登录。
  2. 如果 #1 未成功,请尝试旧算法。
  3. 如果#2 成功,数据库表中的密码哈希和盐值将被更新以符合标准 FOSUserBundle 方法

我一直在阅读有关如何插入服务以使其正常工作的信息,我认为我所拥有的以下内容在理论上似乎是正确的 - 如果没有任何更正/指导,我将不胜感激,因为我无法做到测试一下!

但是,我不确定应该如何将它们全部连接到 Symfony 中,以便在第 1 步失败时正常的 FOSUserBundle 进程将执行第 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);
    }
}

旧版密码编码器:

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));

    }
}

【问题讨论】:

    标签: passwords fosuserbundle symfony


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      security:
        hide_user_not_found: false
        encoders:
          Cerad\Bundle\UserBundle\Entity\User: # Replace with your user class
              id: cerad_user.user_encoder # Replace with the service id for your encoder
      

      这应该足以让您的编码器插入。

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

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

      class MyEncoder extends BCryptPasswordEncoder
      {
        function isPasswordValid($encoded,$raw,$salt)
        {
          // Check the bcrypt
          if (parent::isPasswordValid($encoded,$raw,$salt)) return true;
      
          // Copied from legacy
          list($salt1,$salt2) = explode(",",$salt);
          return 
            !$this->isPasswordTooLong($raw) &&
             $this>comparePasswords($encoded,sha1($salt1.$raw.$salt2));
      

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

      【讨论】:

      • 谢谢Cerad - 虽然我很清楚,这不是security: 部分你提到的与我已经在security.yml 下的问题相同吗?我对自定义编码器的尝试是LegacyPasswordEncoder 在我的问题中(我将在今晚更新它以扩展BCrptPasswordEncoder),其中包含我对您提到的自定义isPasswordValid 方法的尝试。这是错的吗?
      • 使用安全文件的编码器部分更新您的问题。我目前看到的只是一个参数。编码器部分是您如何将特定用户实体类映射到实际编码器。这是另一种解释:stackoverflow.com/questions/8771655/….
      • 很抱歉 - 我复制了错误的部分(!)。我已经用encoder: 部分更新了我的问题。我想我对BCryptPasswordEncoder 如何首先检查密码是否有效感到困惑,如果不是,则调用LegacyPasswordEncoder
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-02
      • 1970-01-01
      • 2015-02-04
      • 1970-01-01
      • 2014-11-21
      • 2018-11-02
      相关资源
      最近更新 更多