Django中如何通过绑定手机号实现用户密码重置?
Django 通过手机号重置用户密码实现方案
1. 先修正模型字段约束
首先需要给UserProfile的mobile字段增加唯一约束,避免多个账号绑定同一个手机号,修改后的models.py代码如下:
from django.db import models from django.contrib.auth.models import User class UserProfile(models.Model): user = models.OneToOneField(User, null=True, on_delete=models.CASCADE) # 增加unique约束,blank和null根据你的业务需求保留 mobile = models.CharField(max_length=15, blank=True, null=True, unique=True) def __str__(self): return self.user.username
修改完成后执行python manage.py makemigrations和python manage.py migrate完成数据库迁移。
2. 实现重置全流程
完整流程分为三个环节:提交手机号发送验证码、验证验证码获取重置凭证、提交新密码完成重置。
2.1 发送验证码接口逻辑
- 前端传入用户输入的手机号
- 后端查询
UserProfile表中是否存在该手机号对应的账号(为了防撞库,无论是否存在都统一返回“如果该手机号已绑定账号,验证码将在5分钟内发送”) - 如果账号存在,生成6位数字验证码,存入缓存(如Redis、Django Session)并设置5分钟有效期
- 调用短信服务商的接口将验证码发送到对应手机号
示例代码(基于FBV):
from django.core.cache import cache from django.http import JsonResponse import random from .models import UserProfile def send_reset_code(request): mobile = request.POST.get("mobile") if not mobile: return JsonResponse({"code": 400, "msg": "请输入手机号"}) # 检查手机号是否存在 try: UserProfile.objects.get(mobile=mobile) except UserProfile.DoesNotExist: return JsonResponse({"code": 200, "msg": "如果该手机号已绑定账号,验证码将在5分钟内发送"}) # 生成验证码 code = random.randint(100000, 999999) # 存入缓存,key用手机号做唯一标识,有效期300秒 cache.set(f"reset_code_{mobile}", code, timeout=300) # 这里调用你的短信发送接口发送code到mobile # send_sms(mobile, code) return JsonResponse({"code": 200, "msg": "验证码已发送"})
2.2 验证码校验接口逻辑
- 前端传入手机号和用户填写的验证码
- 后端从缓存中取出对应手机号的验证码,判断是否和传入的一致
- 校验通过后,用Django自带的
signing模块生成带过期时间的重置token,返回给前端作为后续重置密码的凭证
示例代码:
from django.core import signing from django.core.cache import cache from django.http import JsonResponse def verify_reset_code(request): mobile = request.POST.get("mobile") input_code = request.POST.get("code") if not all([mobile, input_code]): return JsonResponse({"code": 400, "msg": "参数不全"}) cache_code = cache.get(f"reset_code_{mobile}") if not cache_code or str(cache_code) != str(input_code): return JsonResponse({"code": 400, "msg": "验证码错误或已过期"}) # 生成有效期15分钟的重置token token = signing.dumps({"mobile": mobile}, salt="reset_pwd_salt", expires_in=900) return JsonResponse({"code": 200, "msg": "验证通过", "reset_token": token})
2.3 密码重置接口逻辑
- 前端传入重置token、新密码
- 后端校验token是否有效,解析出对应的手机号
- 查询到对应用户后,调用Django自带的
set_password()方法修改密码 - 清空缓存中对应的验证码,完成重置
示例代码:
from django.core import signing from django.http import JsonResponse from .models import UserProfile def reset_password(request): reset_token = request.POST.get("reset_token") new_pwd = request.POST.get("new_password") if not all([reset_token, new_pwd]): return JsonResponse({"code":400, "msg":"参数不全"}) # 校验token try: data = signing.loads(reset_token, salt="reset_pwd_salt", max_age=900) mobile = data.get("mobile") except signing.BadSignature: return JsonResponse({"code":400, "msg":"重置凭证无效或已过期"}) # 获取用户 try: profile = UserProfile.objects.get(mobile=mobile) except UserProfile.DoesNotExist: return JsonResponse({"code":400, "msg":"用户不存在"}) # 修改密码 profile.user.set_password(new_pwd) profile.user.save() # 清空验证码缓存 cache.delete(f"reset_code_{mobile}") return JsonResponse({"code":200, "msg":"密码重置成功,请重新登录"})
注意事项
- 要给短信接口加请求频率限制,避免被恶意刷短信
- 新密码要做强度校验,比如长度不低于8位,包含字母数字等
salt值要保存在配置文件里,不要硬编码在业务代码中- 密码修改完成后,可选清理该用户的所有登录session,强制所有设备重新登录
内容的提问来源于stack exchange,提问作者Yabesh
相关产品推荐
相关产品推荐

