Django PasswordResetConfirmView失效,密码无法重置求助
问题描述
在Django中实现了自定义密码重置功能,相关代码如下:
View代码
def f_forget_password(request): ctx = dict() if request.method == "POST": password_reset_form = PasswordResetForm(request.POST) if password_reset_form.is_valid(): to_email = password_reset_form.cleaned_data['email'] to_email=to_email.lower() associated_users = User.objects.filter(Q(email=to_email)) if associated_users.exists(): if len(associated_users)!=1: return HttpResponse('Email Is Invalid.') current_site = get_current_site(request) for user in associated_users: mail_subject = "Password Reset Requested" email_template_name = "password/password_reset_email.txt" uid=urlsafe_base64_encode(force_bytes(user.pk)) c = { "email":user.email, 'domain':current_site.domain, 'site_name': 'mysit', "uid": uid, "user": user, 'token': account_activation_token.make_token(user), } try: message = loader.render_to_string(email_template_name, c) email = EmailMessage( mail_subject, message, to=[to_email] ) email.send() except Exception as e: return HttpResponse('Invalid header found.<br/>') return redirect ("/password_reset/done/") else: return HttpResponse('Email not found.') template = loader.get_template('password/forget_password.html') response = HttpResponse(template.render(ctx, request),content_type='text/html') return response
URL配置
path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(template_name='password/password_reset_done.html'), name='password_reset_done'), path('reset/<uidb64>/<token>', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), path('reset/done/', auth_views.PasswordResetCompleteView.as_view(template_name='password/password_reset_complete.html'), name='password_reset_complete'),
Token生成代码
class TokenGenerator(PasswordResetTokenGenerator): def _make_hash_value(self, user, timestamp): return ( six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active) ) account_activation_token = TokenGenerator()
点击密码重置链接时出现错误:
Password reset unsuccessful
The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
解决方案
问题核心是自定义Token生成器的哈希逻辑与Django内置PasswordResetConfirmView的校验逻辑不匹配。
Django默认的PasswordResetConfirmView使用内置的PasswordResetTokenGenerator进行Token校验,而你自定义的生成器缺少了用户密码哈希的计算,导致校验时无法匹配。
具体修复步骤:
修改自定义Token生成器的哈希计算逻辑,对齐内置实现:
内置生成器的哈希值包含用户主键、时间戳、激活状态和密码哈希,更新token.py代码:from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.utils import six class TokenGenerator(PasswordResetTokenGenerator): def _make_hash_value(self, user, timestamp): return ( six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active) + six.text_type(user.password) ) account_activation_token = TokenGenerator()(如果使用Django 3.1及以上版本,
six已被弃用,直接替换为str()即可)验证邮件模板的链接格式:
检查password_reset_email.txt中的重置链接,确保uidb64和token参数完整传递,没有被转义或截断,示例格式:Please click the following link to reset your password: http://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}可选:直接使用内置Token生成器:
若无需特殊自定义逻辑,直接使用Django自带的生成器即可避免匹配问题:from django.contrib.auth.tokens import PasswordResetTokenGenerator account_activation_token = PasswordResetTokenGenerator()
内容的提问来源于stack exchange,提问作者mohamadreza ch
相关产品推荐
相关产品推荐

