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

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校验,而你自定义的生成器缺少了用户密码哈希的计算,导致校验时无法匹配。

具体修复步骤:

  1. 修改自定义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()即可)

  2. 验证邮件模板的链接格式:
    检查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 %}
    
  3. 可选:直接使用内置Token生成器:
    若无需特殊自定义逻辑,直接使用Django自带的生成器即可避免匹配问题:

    from django.contrib.auth.tokens import PasswordResetTokenGenerator
    
    account_activation_token = PasswordResetTokenGenerator()
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 12:55:14