【问题标题】:PasswordResetConfirmView is not working proeprly?PasswordResetConfirmView 工作不正常?
【发布时间】:2020-02-18 06:48:02
【问题描述】:

这里我没有使用PasswordResetView,因为我通过我的动态电子邮件配置发送电子邮件,所以为此我制作了自己的视图,它使用PasswordResetTokenGenerator 生成令牌,并且还将电子邮件发送给用户。我电子邮件中的密码重置链接看起来像这样http://127.0.0.1:8000/password-reset/confirm/NQ/5as-b3502199950ff028a6ef/

但是在单击该链接后,它会重定向到 password_reset_confirm,这很好,但在此视图中,{{form.as_p}} 不起作用。它只显示按钮,但在使用 auth-views.PasswordresetView 之前,表单正在工作,但现在没有在模板中传递表单。

我该如何解决这个问题?

urls.py

 path('password-reset/',views.send_password_reset_email,name='password_reset'),
    path('password-reset/done/',auth_views.PasswordResetDoneView.as_view(template_name='password_reset_done.html'),name='password_reset_done'),
    path('password-reset/confirm/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(template_name='password_reset_confirm.html',                                                 success_url=reverse_lazy('password_reset_complete'),),name='password_reset_confirm'),

views.py

def send_password_reset_email(request):
    form = CustomPasswordResetForm()
    if request.method == 'POST':
        form = CustomPasswordResetForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            user = get_user_model().objects.get(email__iexact=email)   
            site = get_current_site(request)
            mail_subject = "Password Reset on {} ".format(site.domain)
            message = render_to_string('password_reset_email.html', {
                "user": user,
                'domain': site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
                'token': activation_token.make_token(user)
            })
            config = EmailConfiguration.objects.order_by('-date').first()
            backend = EmailBackend(host=config.email_host, port=config.email_port, username=config.email_host_user,
                                   password=config.email_host_password, use_tls=config.email_use_tls)
            email = EmailMessage(subject=mail_subject, body=message, from_email=config.email_host_user, to=[user.email],
                                 connection=backend)
            email.send()
            return redirect('password_reset_done')

    return render(request, 'password_reset.html',{'form':form})

password_reset_email.html

{% block reset_link %}
http://{{domain}}{% url 'password_reset_confirm' uidb64=uid token=token  %}
{% endblock %}

password_reset_confirm.html

 <form action="" method="post">
      {% csrf_token %}
       {{form.as_p}}
    <button type="submit" class="btn btn-info">Reset Password</button>
  </form>

tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six

class TokenGenerate(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.id)+six.text_type(timestamp)+six.text_type(user.is_active)
        )

activation_token=TokenGenerate()

【问题讨论】:

  • PasswordResetConfirmView的出处。如果self.validlink == False,它将context['form'] 设置为None。尝试在模板中打印{{ title }},它可能会显示“密码重置失败”。似乎找不到具有正确 ID 的用户。
  • 你不应该在你的 uid 末尾有 .decode()
  • @dirkgroten 你说得对,它说password reset unsuccessful 我也删除了.decode。那么如何解决这个问题?
  • 在你的 django shell 中,尝试:uid = force_text(urlsafe_base64_decode(uidb64)) 然后User.objects.get(pk=uid)
  • 另外,请确保您使用与PasswordResetConfirmView 相同的token_generator,我看不出您从哪里导入activation_token,但它可能是错误的。再次,查看 Django 源代码来做同样的事情。

标签: python django


【解决方案1】:

您对PasswordResetTokenGenerator 进行了子类化,因此在验证令牌时还需要使用它。 Django 让这一切变得简单,PasswordResetConfirmView 具有 token_generator 作为类属性,因此您只需对其进行子类化以覆盖它正在使用的令牌生成器:

class CustomPasswordResetConfirmView(auth_views.PasswordResetConfirmView):
    token_generator = activation_token

然后在您的 url 模式中将此视图用于 'password-reset/confirm/&lt;uidb64&gt;/&lt;token&gt;/' 路径。

您还需要确保正确编码uid。你可以通过检查你的 django shell 来验证你做的是否正确:

uid = force_text(urlsafe_base64_decode(uidb64))
User.objects.get(pk=uid)

应该返回用户。

请注意,您的 _make_hash_value 方法并不安全:它总是会在时间戳保持有效的一天内生成相同的哈希值。因此,即使用户更改了密码,它也可以多次重复使用,任何有权访问电子邮件的人都可以再次重置密码。这就是为什么Django的生成器原来的_make_hash_value使用了密码,所以改了之后就不能再使用了。

更糟糕的是,我可以为您的任何用户制作令牌,并通过这种方式重置他们的密码,因为除了他们的 id (整数)之外我不需要知道任何内容,所以我可以尝试直到遇到存在于您的数据库中的 id。

【讨论】:

  • 评论不用于扩展讨论;这个对话是moved to chat
  • 错误:__init__() 接受 1 个位置参数,但给出了 2 个。请帮帮我
  • @Shoaib21 该错误意味着您将一个参数传递给一个类的初始化程序以实例化它不应该存在的。由于您没有向我们展示您的错误的任何上下文(我们不知道哪个类的 __init__() 方法引发了错误),因此无法判断。整个错误跟踪会有所帮助。但您应该将其作为新问题提交。
猜你喜欢
  • 2020-04-23
  • 2023-04-10
  • 2015-01-16
  • 1970-01-01
  • 2016-08-02
  • 2013-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多