python - PasswordResetConfirmView 无法正常工作?
问题描述
在这里我没有使用 PasswordResetView
,因为我通过我的动态电子邮件配置发送电子邮件,所以为此我制作了自己的视图,它使用生成令牌PasswordResetTokenGenerator
并将电子邮件发送给用户。我电子邮件中的密码重置链接如下所示http://127.0.0.1:8000/password-reset/confirm/NQ/5as-b3502199950ff028a6ef/
但是在单击该链接后,它重定向到password_reset_confirm
哪个很好,但在此视图{{form.as_p}}
中不起作用。它只显示按钮,但在使用auth-views.PasswordresetView
表单之前工作但现在表单没有在模板中传递。
我该如何解决这个问题?
网址.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'),
视图.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>
令牌.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()
解决方案
您对 进行了子类化,PasswordResetTokenGenerator
因此在验证令牌时还需要使用它。Django 使这很容易,它PasswordResetConfirmView
具有token_generator
as 类属性,因此您只需要对其进行子类化以覆盖它正在使用的令牌生成器:
class CustomPasswordResetConfirmView(auth_views.PasswordResetConfirmView):
token_generator = activation_token
然后在您的 url 模式中使用此视图作为'password-reset/confirm/<uidb64>/<token>/'
路径。
您还需要确保uid
正确编码。您可以通过签入您的 django shell 来验证您是否正确执行此操作:
uid = force_text(urlsafe_base64_decode(uidb64))
User.objects.get(pk=uid)
这应该返回用户。
请注意,您的_make_hash_value
方法不安全:它总是会在时间戳保持有效的一天内生成相同的哈希。因此,即使用户更改了密码,它也可以多次重复使用,任何有权访问电子邮件的人都可以再次重置密码。这就是为什么原来_make_hash_value
Django的generator使用的是密码,所以改了之后就不能再使用了。
更糟糕的是,我可以为您的任何用户制作令牌,并以这种方式重置他们的密码,因为除了他们的 id (整数)之外我不需要知道任何东西,所以我可以尝试直到找到一个存在的 id在你的数据库中。
推荐阅读
- python - 制表符错误:缩进中制表符和空格的使用不一致
- javascript - 用于替换特定单词的正则表达式
- c - 如何为复杂语句创建示例?
- azure - why azure subnets don't have subnet.id param
- kubernetes - 在 Kubernetes master 中添加已移除的 etcd 成员
- java - Test apache pulsar functions in an embedded standalone environment
- php - 使用 php 将 sql 代码写入新的 php 文件失败
- python - selenium python中的函数driver.delete_all_cookies()不会删除所有cookie
- reactjs - 无法为连接的高阶组件获得强类型化
- javascript - JavaScript arguments 关键字和多个参数 ...args