You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中用pbkdf2_sha256哈希MySQL存量明文密码并兼容老用户登录

处理存量明文密码,让老用户无需重新注册即可登录

我是Django新手,现在有一批存储为明文的用户密码,需要编写脚本对这些密码进行哈希处理,同时要让存量老用户不用创建新账号就能登录。我已经实现了新用户的注册和登录功能,代码如下:

@admin_login_required
def add_emp(request):
    if request.method == 'POST':
        user_name = request.POST['user_name']
        user_email = request.POST['user_email']
        user_otj = request.POST['user_otj']
        user_password = pwo.generate()
        user_password1 = make_password(user_password)
        empObj = User.objects.create(user_name=user_name, user_email=user_email, user_password=user_password1, user_otj=user_otj)
        if empObj:
            subject = 'Advanced Analytics Portal - Login Info'
            message = f'Name : {user_name}, \\n Email : {user_email}, \\n Password : {user_password} \\n FROM - AA Portal'
            email_from = settings.EMAIL_HOST_USER
            send_mail(subject, message, email_from, [user_email])
            messages.success(request, "Employee was added successfully!")
            return HttpResponseRedirect('/create-emp')
        else:
            messages.error(request, "Some error was occurred!")
            return HttpResponseRedirect('/create-emp')
    return render(request, 'AddEmp.html')

def user_login(request):
    if request.method == "POST":
        user_email = request.POST['user_email']
        user_password = request.POST['user_password']
        user_details = User.objects.filter(user_email=user_email).first()

        if user_details and check_password(user_password, user_details.user_password):
            request.session['logged_in'] = True
            request.session['user_email'] = user_details.user_email
            request.session['u_id'] = user_details.user_email
            request.session['user_name'] = user_details.user_name
            request.session['u_type'] = "emp"
            return HttpResponseRedirect('/user_index')
        else:
            return render(request, 'EmpLogin.html', {'msg': "0"})
    else:
        return render(request, 'EmpLogin.html')

解决方案

一、修改登录逻辑,兼容明文与哈希密码

现在的登录逻辑只支持哈希密码验证,需要调整为:先尝试哈希密码验证,失败后再匹配明文密码,若明文匹配成功,立即将密码哈希后更新到数据库,确保下次登录走正常哈希流程。

修改后的user_login函数:

def user_login(request):
    if request.method == "POST":
        user_email = request.POST['user_email']
        user_password = request.POST['user_password']
        user_details = User.objects.filter(user_email=user_email).first()

        if user_details:
            # 优先验证哈希密码(新用户或已更新的老用户)
            if check_password(user_password, user_details.user_password):
                # 设置会话并跳转
                request.session['logged_in'] = True
                request.session['user_email'] = user_details.user_email
                request.session['u_id'] = user_details.user_email
                request.session['user_name'] = user_details.user_name
                request.session['u_type'] = "emp"
                return HttpResponseRedirect('/user_index')
            else:
                # 哈希验证失败,尝试明文匹配
                if user_details.user_password == user_password:
                    # 明文匹配成功,更新为哈希密码
                    hashed_pw = make_password(user_password)
                    user_details.user_password = hashed_pw
                    user_details.save()
                    # 设置会话并跳转
                    request.session['logged_in'] = True
                    request.session['user_email'] = user_details.user_email
                    request.session['u_id'] = user_details.user_email
                    request.session['user_name'] = user_details.user_name
                    request.session['u_type'] = "emp"
                    return HttpResponseRedirect('/user_index')
                else:
                    # 两种验证都失败
                    return render(request, 'EmpLogin.html', {'msg': "0"})
        else:
            # 用户不存在
            return render(request, 'EmpLogin.html', {'msg': "0"})
    else:
        return render(request, 'EmpLogin.html')

二、批量转换明文密码(主动处理所有存量用户)

如果不想等用户登录时才更新密码,可以通过以下方式批量转换:

方法1:使用Django Shell执行

进入项目根目录,运行:

python manage.py shell

然后执行代码:

from django.contrib.auth.hashers import make_password
from your_app.models import User  # 替换为你的User模型所在app名

# 筛选出所有非哈希格式的用户(Django哈希密码以pbkdf2_sha256$、bcrypt$、argon2$开头)
plain_pw_users = User.objects.exclude(user_password__startswith='pbkdf2_sha256$').exclude(user_password__startswith='bcrypt$').exclude(user_password__startswith='argon2$')

for user in plain_pw_users:
    user.user_password = make_password(user.user_password)
    user.save()
    print(f"已更新用户 {user.user_email} 的密码为哈希格式")

方法2:编写自定义管理命令

  1. 在你的app下创建management/commands目录(无则新建),创建convert_plain_passwords.py文件:
from django.core.management.base import BaseCommand
from django.contrib.auth.hashers import make_password
from your_app.models import User  # 替换为你的User模型路径

class Command(BaseCommand):
    help = '批量将明文用户密码转换为哈希格式'

    def handle(self, *args, **options):
        plain_pw_users = User.objects.exclude(
            user_password__startswith='pbkdf2_sha256$'
        ).exclude(
            user_password__startswith='bcrypt$'
        ).exclude(
            user_password__startswith='argon2$'
        )

        count = 0
        for user in plain_pw_users:
            user.user_password = make_password(user.user_password)
            user.save()
            count += 1
        self.stdout.write(self.style.SUCCESS(f'成功更新 {count} 个用户的密码为哈希格式'))
  1. 在终端运行命令:
python manage.py convert_plain_passwords

三、后续注意事项

  • 保持现有新用户注册逻辑不变(已用make_password处理密码,符合规范)
  • 批量转换后,建议测试几个老用户的登录流程,确保正常
  • 后续绝对禁止存储明文密码,所有密码入库前必须经过哈希处理

内容的提问来源于stack exchange,提问作者JHS99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 06:37:15