如何在Django模型及Admin中使用MySQL SHA2(256)函数存储密码?
解决方案
你无法直接让Django模型调用MySQL的SHA2()函数自动处理密码哈希,需要通过自定义逻辑实现,以下是几种简洁的实现方式:
方法1:重写模型的save方法
这是最直接的实现,在模型保存前对密码进行哈希处理,确保无论通过Admin还是其他方式创建/更新用户,密码都会被自动哈希:
import hashlib from django.db import models class Users(models.Model): username = models.CharField(max_length=30) password = models.CharField(max_length=128) status = models.IntegerField() valid_from = models.DateTimeField() valid_to = models.DateTimeField() online = models.IntegerField() ip = models.CharField(max_length=20) created = models.DateTimeField() def __str__(self): return f'{self.username}' def save(self, *args, **kwargs): # 仅当密码为明文时进行哈希(假设明文不会刚好是64位SHA256结果) if len(self.password) != 64: self.password = hashlib.sha256(self.password.encode('utf-8')).hexdigest() super().save(*args, **kwargs)
方法2:使用Django信号(更灵活)
如果不想修改模型的save方法,可以用pre_save信号在实例保存前自动处理密码:
import hashlib from django.db import models from django.db.models.signals import pre_save from django.dispatch import receiver class Users(models.Model): username = models.CharField(max_length=30) password = models.CharField(max_length=128) status = models.IntegerField() valid_from = models.DateTimeField() valid_to = models.DateTimeField() online = models.IntegerField() ip = models.CharField(max_length=20) created = models.DateTimeField() def __str__(self): return f'{self.username}' @receiver(pre_save, sender=Users) def hash_user_password(sender, instance, **kwargs): # 新建用户时直接哈希 if instance.pk is None: instance.password = hashlib.sha256(instance.password.encode('utf-8')).hexdigest() else: # 更新用户时,仅当密码被修改才哈希 old_user = sender.objects.get(pk=instance.pk) if old_user.password != instance.password: instance.password = hashlib.sha256(instance.password.encode('utf-8')).hexdigest()
方法3:强制使用MySQL的SHA2()函数(不推荐)
如果必须依赖MySQL的内置函数生成哈希,可以通过原生SQL查询获取哈希值,但这种方式会让代码绑定MySQL,失去跨数据库兼容性:
from django.db import models from django.db.models import RawQuerySet class Users(models.Model): username = models.CharField(max_length=30) password = models.CharField(max_length=128) status = models.IntegerField() valid_from = models.DateTimeField() valid_to = models.DateTimeField() online = models.IntegerField() ip = models.CharField(max_length=20) created = models.DateTimeField() def __str__(self): return f'{self.username}' def save(self, *args, **kwargs): if len(self.password) != 64: # 调用MySQL的SHA2函数生成哈希 hash_result = RawQuerySet(raw_query="SELECT SHA2(%s, 256) AS hashed_pwd", params=[self.password], model=Users) self.password = hash_result[0].hashed_pwd super().save(*args, **kwargs)
注意事项
- 优先使用Python内置的
hashlib实现哈希,避免依赖特定数据库,保证代码可移植性。 - 确保
password字段的max_length足够长(SHA256哈希是64个字符,你设置的128完全足够)。 - 如果后续需要更安全的密码存储,建议改用Django自带的密码哈希系统(如PBKDF2),它会自动处理加盐和迭代哈希,比单纯的SHA256更安全。
内容的提问来源于stack exchange,提问作者Stepan Kutaj
相关产品推荐
相关产品推荐

