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

Django中安全码字段哈希存储与校验,是否需要自定义认证后端?

方案选择建议

两种方案都可以实现需求,可根据你的业务复杂度选择:

方案1:直接在用户模型中新增校验方法(适合业务简单、仅需在少数场景校验安全码的情况)

  • 优势:实现成本极低,不需要修改Django认证体系默认配置,逻辑高度内聚在用户模型中
  • 实现注意事项:
    1. 首先需要修改security_code字段类型,原IntegerField无法存储哈希字符串,需改为CharField,max_length设置为128即可覆盖所有Django默认哈希算法的输出长度
    2. 直接复用Django内置的密码校验逻辑即可,不需要重复造轮子
    3. 生成安全码的逻辑中,必须用make_password处理原始安全码后再存入数据库
  • 代码示例:
from django.contrib.auth.hashers import check_password, make_password
import random
from django.utils import timezone

class CustomUser(AbstractBaseUser,PermissionsMixin):
    phone_number = models.CharField(verbose_name="Mobile Number", max_length=11, unique=True, blank=False, null=False)
    # 修改字段类型存储哈希值
    security_code = models.CharField(verbose_name="Security Code", max_length=128, null=True)
    security_code_creation = models.DateTimeField(auto_now=True)

    def check_security_code(self, raw_code: str) -> bool:
        # 直接复用内置密码校验逻辑,自动处理哈希算法匹配、加盐校验
        return check_password(raw_code, self.security_code)

# 视图层发送安全码逻辑示例
def send_login_code(request):
    phone = request.POST.get("phone")
    user = CustomUser.objects.get(phone_number=phone)
    # 生成6位随机安全码
    raw_code = str(random.randint(100000, 999999))
    # 哈希后存入数据库
    user.security_code = make_password(raw_code)
    user.security_code_creation = timezone.now()
    user.save()
    # 调用短信接口发送原始安全码给用户
    send_sms(phone, f"您的登录验证码是{raw_code},5分钟内有效")

校验时直接调用user.check_security_code(用户输入的验证码)即可得到校验结果。

方案2:自定义认证后端(适合需要兼容Django默认authenticate方法、多登录方式统一入口、依赖Django内置权限体系的场景)

如果你的业务需要用Django自带的authenticate函数统一处理所有登录请求,或者后续还要扩展更多登录方式,推荐自定义认证后端,和密码登录逻辑完全解耦。

  • 实现步骤:
    1. 先按方案1的要求修改用户模型,新增check_security_code方法
    2. 新建认证后端类,实现authenticate和get_user方法
    3. 在settings.py的AUTHENTICATION_BACKENDS配置中新增自定义后端
  • 代码示例:
# 新建auth_backends.py文件
from django.contrib.auth.backends import BaseBackend
from django.utils import timezone
from .models import CustomUser

class SecurityCodeAuthBackend(BaseBackend):
    def authenticate(self, request, phone=None, code=None, **kwargs):
        if not phone or not code:
            return None
        try:
            user = CustomUser.objects.get(phone_number=phone)
        except CustomUser.DoesNotExist:
            return None
        # 同时校验安全码和有效期,示例设置5分钟有效期
        if user.check_security_code(code) and (timezone.now() - user.security_code_creation).total_seconds() < 300:
            return user
        return None

    def get_user(self, user_id):
        try:
            return CustomUser.objects.get(pk=user_id)
        except CustomUser.DoesNotExist:
            return None

在settings.py中添加配置:

AUTHENTICATION_BACKENDS = [
    # 保留默认的密码登录后端
    'django.contrib.auth.backends.ModelBackend',
    # 新增安全码登录后端
    '你的应用名.auth_backends.SecurityCodeAuthBackend',
]

之后安全码登录可以直接调用Django内置的统一登录方法:

from django.contrib.auth import authenticate, login

user = authenticate(request, phone=request.POST.get("phone"), code=request.POST.get("code"))
if user is not None:
    login(request, user)
    # 登录成功后续逻辑

注意必须给安全码加过期校验,避免安全码长期有效导致账户风险,建议有效期设置为1~5分钟。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 14:18:03