从Django迁移用户密码至Symfony 3的实现方案咨询
Django 到 Symfony 3 用户密码迁移实操指南
嘿,我刚好有过类似的迁移经验,结合你提到的思路,给你整理一套可落地的密码迁移方案:
一、先搞懂Django的密码存储逻辑
Django的用户密码是按算法$盐$哈希值的格式存在数据库里的,比如典型的pbkdf2_sha256$260000$abc123xyz$def456uvw。你需要先确认你的Django项目用的是哪种加密算法(常见的有pbkdf2_sha256、pbkdf2_sha1、bcrypt)。
二、在Symfony 3里自定义密码编码器
Symfony默认的编码器不直接兼容Django的格式,所以我们要写一个自定义编码器来验证旧密码:
// src/AppBundle/Security/DjangoPasswordEncoder.php namespace AppBundle\Security; use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder; class DjangoPasswordEncoder extends BasePasswordEncoder { public function encodePassword($raw, $salt) { // 这个方法主要用于编码新密码,我们暂时用不上,按接口要求返回空即可 return ''; } public function isPasswordValid($encoded, $raw, $salt) { // 拆分Django的密码格式 $parts = explode('$', $encoded); if (count($parts) !== 3) { return false; } list($algorithm, $djangoSalt, $djangoHash) = $parts; // 根据不同算法做验证 switch ($algorithm) { case 'pbkdf2_sha256': // 注意:迭代次数要和你的Django版本一致,默认是260000(Django 2.0+) $iterations = 260000; $hash = hash_pbkdf2('sha256', $raw, $djangoSalt, $iterations, 0, true); return hash_equals(base64_encode($hash), $djangoHash); case 'pbkdf2_sha1': $iterations = 260000; $hash = hash_pbkdf2('sha1', $raw, $djangoSalt, $iterations, 0, true); return hash_equals(base64_encode($hash), $djangoHash); case 'bcrypt': // Django的bcrypt格式和Symfony原生兼容,直接用password_verify就行 return password_verify($raw, $encoded); default: return false; } } }
三、配置Symfony使用自定义编码器
1. 注册编码器服务
在app/config/services.yml里添加:
services: app.django_password_encoder: class: AppBundle\Security\DjangoPasswordEncoder
2. 配置安全编码器
在app/config/security.yml里指定用户实体使用我们的自定义编码器:
security: encoders: AppBundle\Entity\User: id: app.django_password_encoder # 其他安全配置(比如防火墙、角色等)保持不变
四、过渡方案:逐步替换为Symfony原生密码
为了避免后续一直依赖自定义编码器,建议在用户第一次登录验证通过后,自动将密码重新编码为Symfony原生格式:
你可以在登录成功的监听器或者控制器里添加这段逻辑:
// 示例:在登录成功后的控制器逻辑中 $user = $this->getUser(); $rawPassword = $request->request->get('_password'); // 获取用户输入的明文密码 // 判断当前密码是Django格式,且验证通过 if (strpos($user->getPassword(), '$') !== false) { $djangoEncoder = $this->get('app.django_password_encoder'); if ($djangoEncoder->isPasswordValid($user->getPassword(), $rawPassword, null)) { // 用Symfony默认编码器重新加密密码 $defaultEncoder = $this->get('security.password_encoder'); $newEncodedPassword = $defaultEncoder->encodePassword($user, $rawPassword); $user->setPassword($newEncodedPassword); // 保存到数据库 $em = $this->getDoctrine()->getManager(); $em->persist($user); $em->flush(); } }
这样用户下次登录时,就会用Symfony原生的编码器验证,逐步完成所有用户密码的迁移。
内容的提问来源于stack exchange,提问作者Miljan Vulovic
相关产品推荐
相关产品推荐

