如何在Django自定义密码重置系统中通过验证码完成用户身份校验
自定义密码重置系统验证码校验实现
现有代码回顾
models.py
class UserProfile(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,related_name="userprofile") forget_password_token = models.CharField(max_length=100,blank=True,null=True) # 后续优化可加字段:forget_password_token_expire = models.DateTimeField(blank=True,null=True) 存储验证码过期时间
发送验证码视图(现有逻辑)
def ForgetPasswordSendCode(request): if request.method == "POST": email = request.POST["email"] User = get_user_model() if not User.objects.filter(email=email).first(): messages.success(request, "Invalid mail") return redirect('members:reset-password') user_obj = User.objects.get(email=email) reset_code = str(rand_number_mail()) #生成随机验证码 profile_obj = UserProfile.objects.get(user=user_obj) profile_obj.forget_password_token = reset_code # 后续优化可加:profile_obj.forget_password_token_expire = timezone.now() + timedelta(minutes=15) 设置15分钟有效期 profile_obj.save() current_site = get_current_site(request) subject = 'Verification Code' context = { 'user_first_name': user_obj.first_name , 'user_last_name': user_obj.last_name , 'domain': current_site.domain, 'reset_code': reset_code } html_body = render_to_string('mail/resetpassword-mail.html', context) to_email = request.POST["email"] email = EmailMultiAlternatives(subject=subject,from_email='noreply@farhyn.com',to=[to_email]) email.attach_alternative(html_body, "text/html") email.send(fail_silently=False) # 可选优化:将邮箱存入session,改密页无需用户重复输入邮箱 request.session['reset_pwd_email'] = to_email messages.success(request, "An password reset code sent to your email") return redirect('members:change-password') #提交邮箱后跳转到密码重置页 return render(request, 'members/password_reset_form.html')
密码重置校验视图实现
from django.contrib.auth.hashers import make_password def ChangePassWordPage(request): if request.method == "POST": # 1. 获取提交参数,如果之前将邮箱存入session可以直接取,不用让用户重复提交邮箱 # email = request.session.get('reset_pwd_email') email = request.POST.get('email') input_code = request.POST.get('reset_code') new_pwd = request.POST.get('new_password') confirm_pwd = request.POST.get('confirm_password') # 2. 基础参数校验 if not all([email, input_code, new_pwd, confirm_pwd]): messages.error(request, "所有字段都不能为空") return render(request,'members/password_change.html') if new_pwd != confirm_pwd: messages.error(request, "两次输入的密码不一致") return render(request,'members/password_change.html') User = get_user_model() # 3. 校验用户是否存在 try: user_obj = User.objects.get(email=email) profile_obj = UserProfile.objects.get(user=user_obj) except (User.DoesNotExist, UserProfile.DoesNotExist): messages.error(request, "用户不存在") return render(request,'members/password_change.html') # 4. 校验验证码是否正确 if profile_obj.forget_password_token != input_code: messages.error(request, "验证码错误") return render(request,'members/password_change.html') # 如果加了过期时间,可新增这步校验(需要提前导入django.utils.timezone) # if timezone.now() > profile_obj.forget_password_token_expire: # messages.error(request, "验证码已过期,请重新发送") # return render(request,'members/password_change.html') # 5. 修改密码 user_obj.password = make_password(new_pwd) user_obj.save() # 6. 清空验证码和session,防止重复使用 profile_obj.forget_password_token = None # profile_obj.forget_password_token_expire = None profile_obj.save() if 'reset_pwd_email' in request.session: del request.session['reset_pwd_email'] messages.success(request, "密码修改成功,请重新登录") return redirect('members:login') return render(request,'members/password_change.html')
前端表单要求
members/password_change.html的表单需要包含以下字段:
- 邮箱输入框(如果没将邮箱存入session的话),name属性为
email - 验证码输入框,name属性为
reset_code - 新密码输入框,name属性为
new_password - 确认密码输入框,name属性为
confirm_password - 提交按钮,请求方式为POST
优化建议
- 给验证码增加15-30分钟的过期时间,避免验证码长期有效带来的安全风险
- 验证码校验通过后立刻清空存储的token,防止同一个验证码被多次使用
- 增加新密码强度校验,限制密码长度、字符类型等,避免弱密码
- 对发送验证码、校验验证码的接口增加频率限制,防止暴力破解和恶意请求
内容的提问来源于stack exchange,提问作者boyenec
相关产品推荐
相关产品推荐

