基于Django的博客系统之登录增加忘记密码(八)

需求

  • 描述: 用户忘记密码时,提供一种重置密码的方法,以便重新获得账户访问权限。
  • 规划:
    • 创建一个包含邮箱输入字段的表单,用于接收用户的重置密码请求。
    • 用户输入注册时使用的邮箱地址,系统发送包含重置密码链接的邮件到用户邮箱。
    • 邮件中包含一个链接,用户点击链接后跳转到重置密码页面,可以设置一个新的密码。

技术难点

1. 邮件发送配置

难点

  • 配置邮件服务器(SMTP)。
  • 确保邮件服务器设置安全可靠,避免出现发送失败或被垃圾邮件拦截。

解决方案

  • settings.py 中正确配置邮件发送相关设置,如 EMAIL_BACKENDEMAIL_HOSTEMAIL_PORTEMAIL_USE_TLSEMAIL_HOST_USEREMAIL_HOST_PASSWORD 等。
  • 选择合适的邮件服务提供商,如 Gmail、SendGrid、Amazon SES 等,并确保你遵守其安全策略和最佳实践。
2. 表单验证与安全

难点

  • 确保输入的邮箱地址有效,并且关联到一个已存在的用户。
  • 防止恶意用户频繁请求重置密码,可能导致的DDoS攻击。

解决方案

  • 使用 Django 的表单验证机制,确保输入的邮箱格式正确。
  • 对重置密码请求进行速率限制(例如,通过 django-ratelimit 库),防止滥用。
3. 生成安全的密码重置令牌

难点

  • 生成唯一且安全的令牌,用于识别用户并防止恶意篡改。
  • 确保令牌具有时效性,防止过期令牌被利用。

解决方案

  • 使用 Django 内置的 default_token_generator,它已经实现了安全的令牌生成和验证机制。
  • 配置令牌的有效期,确保在合理的时间内进行密码重置操作。
4. URL 编码和解码

难点

  • 在生成密码重置链接时,需要对用户的ID进行编码,确保URL安全性。
  • 在用户点击重置链接时,需要正确解码并验证用户身份。

解决方案

  • 使用 urlsafe_base64_encodeurlsafe_base64_decode 进行安全的编码和解码。
  • 在重置视图中检查令牌的有效性和用户的存在性。
5. 前端模板和用户体验

难点

  • 设计友好且易用的前端页面,确保用户能够轻松地完成密码重置操作。
  • 提示用户在不同步骤中所需的信息,例如,邮件发送成功提示、密码重置成功提示等。

解决方案

  • 使用 Django 模板语言(Django Template Language, DTL)创建清晰简洁的前端页面。
  • 提供用户友好的错误提示和成功提示,增强用户体验。
6. 用户密码重置表单的安全性

难点

  • 确保密码重置表单的安全性,防止CSRF攻击。
  • 在重置密码时,对新密码进行强度验证,确保密码安全。

解决方案

  • 使用 Django 的 CSRF 保护机制,在表单中添加 {% csrf_token %}
  • 使用 Django 自带的 SetPasswordForm,它会对新密码进行强度验证。
总结

尽管实现忘记密码功能涉及多个技术难点,但通过 Django 提供的内置功能和第三方库,可以较为顺利地解决这些问题。关键在于确保每一步的安全性和用户体验,避免潜在的安全漏洞和用户困扰。

技术实现步骤详细说明

1. 用户请求密码重置

用户在登录页面点击“忘记密码”链接,进入请求密码重置页面。

2. 用户填写邮箱并提交表单

用户在请求密码重置页面输入注册时使用的邮箱地址并提交表单。

3. 验证邮箱是否存在于数据库

系统接收到表单提交请求,检查数据库中是否存在该邮箱地址对应的用户。

4. 生成密码重置令牌和UID

如果邮箱地址有效,系统生成密码重置令牌和UID,用于唯一标识用户和验证请求的有效性。

5. 发送包含重置链接的电子邮件

系统通过配置好的邮件服务器,向用户发送包含密码重置链接的电子邮件。链接中包含UID和令牌。

6. 用户点击重置链接,进入重置页面

用户收到电子邮件,点击邮件中的重置链接,进入密码重置页面。

7. 验证令牌和UID是否有效

系统接收到用户点击链接的请求,验证链接中的UID和令牌是否有效,如果无效则提示错误信息。

8. 用户填写新密码并提交表单

用户在密码重置页面输入新密码并提交表单。

9. 验证新密码并更新用户密码

系统接收到表单提交请求,验证新密码的有效性,并更新数据库中用户的密码。

10. 密码重置成功,提示用户登录

密码更新成功后,系统提示用户密码已重置成功,用户可以使用新密码登录。

忘记密码功能技术实现流程图

+--------------------------+
|      用户请求密码重置       |
+--------------------------+|v
+--------------------------+
| 用户填写邮箱并提交表单      |
+--------------------------+|v
+--------------------------+
|   验证邮箱是否存在于数据库    |
+--------------------------+|v
+--------------------------+
| 生成密码重置令牌和UID       |
+--------------------------+|v
+--------------------------+
| 发送包含重置链接的电子邮件    |
+--------------------------+|v
+--------------------------+
| 用户点击重置链接,进入重置页面 |
+--------------------------+|v
+--------------------------+
|   验证令牌和UID是否有效     |
+--------------------------+|v
+--------------------------+
| 用户填写新密码并提交表单      |
+--------------------------+|v
+--------------------------+
|   验证新密码并更新用户密码    |
+--------------------------+|v
+--------------------------+
|   密码重置成功,提示用户登录   |
+--------------------------+

实现步骤

步骤 1: 配置邮件发送

首先,确保你在 settings.py 中配置了邮件发送功能,以QQ为例,根据这个文档设置smtp:

# Email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@example.com'
EMAIL_HOST_PASSWORD = '授权码'
DEFAULT_FROM_EMAIL = 'your-email@example.com'

确保你的email开通了SMTP功能,获得授权码,如下:

在这里插入图片描述

在这里插入图片描述

成功开启SMTP服务后,邮件设置页面如下:

在这里插入图片描述

步骤 2: 创建密码重置表单

创建一个表单用于输入用户的邮箱地址:

from django import formsclass PasswordResetRequestForm(forms.Form):email = forms.EmailField(label="Enter your email", max_length=254)

步骤 3: 创建视图

创建两个视图,一个用于请求密码重置链接,另一个用于实际重置密码。

from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
from django.shortcuts import render, redirect
from django.urls import reverse
from .forms import PasswordResetRequestForm
from django.contrib.auth.forms import SetPasswordFormclass PasswordResetRequestView(View):def get(self, request):form = PasswordResetRequestForm()return render(request, 'password_reset_request.html', {'form': form})def post(self, request):form = PasswordResetRequestForm(request.POST)if form.is_valid():email = form.cleaned_data['email']user = User.objects.filter(email=email).first()if user:token = default_token_generator.make_token(user)uid = urlsafe_base64_encode(force_bytes(user.pk))site = get_current_site(request)link = request.build_absolute_uri(reverse('password_reset_confirm', kwargs={'uidb64': uid, 'token': token}))mail_subject = 'Reset your password'message = render_to_string('password_reset_email.html', {'user': user,'domain': site.domain,'uid': uid,'token': token,'link': link,})send_mail(mail_subject, message, 'your-email@example.com', [email])return redirect('password_reset_done')return render(request, 'password_reset_request.html', {'form': form})class PasswordResetConfirmView(View):def get(self, request, uidb64=None, token=None):uid = urlsafe_base64_decode(uidb64).decode()user = User.objects.get(pk=uid)if default_token_generator.check_token(user, token):form = SetPasswordForm(user)return render(request, 'password_reset_confirm.html', {'form': form, 'user': user})else:return HttpResponse('Token is invalid!')def post(self, request, uidb64=None, token=None):uid = urlsafe_base64_decode(uidb64).decode()user = User.objects.get(pk=uid)form = SetPasswordForm(user, request.POST)if form.is_valid():form.save()return redirect('password_reset_complete')return render(request, 'password_reset_confirm.html', {'form': form})

步骤 4: 创建模板

password_reset_request.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>请求密码重置</title><link rel="stylesheet" href="{% static 'blog/css/post_list.css' %}">
</head>
<body><h2>请求密码重置</h2><form method="post">{% csrf_token %}{{ form.as_p }}<button type="submit">发送密码重置链接</button></form>
</body>
</html>
password_reset_email.html
<p>Hi {{ user.username }},</p>
<p>点击下面的链接重置你的密码:</p>
<p><a href="{{ link }}">{{ link }}</a></p>
password_reset_confirm.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>重置密码</title><link rel="stylesheet" href="{% static 'blog/css/post_list.css' %}">
</head>
<body><h2>重置密码</h2><form method="post">{% csrf_token %}{{ form.as_p }}<button type="submit">重置密码</button></form>
</body>
</html>

步骤 5: 配置 URL

urls.py 文件中添加相应的 URL 路径:

from django.urls import path
from .views import PasswordResetRequestView, PasswordResetConfirmViewurlpatterns = [path('password_reset/', PasswordResetRequestView.as_view(), name='password_reset_request'),path('password_reset/done/', TemplateView.as_view(template_name='password_reset_done.html'), name='password_reset_done'),path('reset/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), name='password_reset_confirm'),path('reset/done/', TemplateView.as_view(template_name='password_reset_complete.html'), name='password_reset_complete'),
]

步骤 6: 测试

  1. 运行开发服务器

    python manage.py runserver
    
  2. 访问密码重置页面

    打开浏览器,访问 http://127.0.0.1:8000/password_reset/ 并测试密码重置功能。

通过这些步骤,你应该能够成功地在 Django 项目中实现忘记密码功能,包括请求密码重置链接、发送重置邮件、以及重置密码。
在这里插入图片描述

登录页面点击忘记密码。进入请求密码重置页面,如下:

在这里插入图片描述

输入email,发动密码重置链接到邮箱地址。发送成功,如下:

在这里插入图片描述

打开邮件箱能看到重置密码的邮件如下:

在这里插入图片描述

点击链接跳转到重置密码页面,如下:

在这里插入图片描述

如果长时间后点击操作,跳转到重置页面会报错如下:

在这里插入图片描述

重置密码成功,如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/846256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CTF本地靶场搭建——基于阿里云ACR实现动态flag题型的创建

接上文&#xff0c;这篇主要是结合阿里云ACR来实现动态flag题型的创建。 这里顺便也介绍一下阿里云的ACR服务。 阿里云容器镜像服务&#xff08;简称 ACR&#xff09;是面向容器镜像、Helm Chart 等符合 OCI 标准的云原生制品安全托管及高效分发平台。 ACR 支持全球同步加速、…

如何恢复 Android 设备上丢失的照片

由于我们的大量数据和日常生活都存储在一台设备上&#xff0c;因此有时将所有照片本地存储在 Android 智能手机或平板电脑上可能是一种冒险行为。无论是由于意外&#xff08;损坏、无意删除&#xff09;&#xff0c;还是您认识的人翻看您的设备并故意删除了您想要保留的照片&am…

从0开始学统计-什么是回归?

1.什么是回归&#xff1f; 回归&#xff08;Regression&#xff09;是统计学中一种用于探索变量之间关系的分析方法。它主要用于预测一个或多个自变量&#xff08;输入变量&#xff09;与因变量&#xff08;输出变量&#xff09;之间的关系。在回归分析中&#xff0c;我们尝试根…

【Leetcode笔记】40.组合总和II

1. 题目要求 这道题目和39.组合总和不一样的地方在于&#xff1a;数组中含有相同的元素。同样地&#xff0c;结果不能含有重复组合。 拿第一个示例来看&#xff0c; candidates [1, 1, 2, 5, 6, 7, 10]问题在于&#xff1a;第一个path[1(index 0), 2]&#xff0c;绝不能出现…

大语言模型实战——最小化模型评测

1. 引言 现在国内外的主流模型&#xff0c;在新模型发布时都会给出很多评测数据&#xff0c;用以说明当前模型在不同数据集上的测评表现&#xff08;如下面llama3发布的评测数据&#xff09;。 这些评测数据是如何给出来的呢&#xff1f;这篇文章会用一个最小化的流程来还原下…

echarts绘制三维柱状图

echarts ECharts 是一个使用 JavaScript 实现的开源可视化库&#xff0c;主要用于数据的可视化展示。ECharts 支持丰富的图表类型&#xff0c;如折线图、柱状图、饼图、地图、K线图等&#xff0c;可以满足不同类型数据的展示需求。 文档地址&#xff1a;echarts 本次所绘制三…

从零开始实现自己的串口调试助手(3) - 显示底部收发,优化串口打开/关闭

注意: 1. 我们要实现自发自收&#xff0c;要将tx&#xff0c;rx连起来 2.发送的 不能是中文符号&#xff0c;因为这可能导致&#xff0c;读取到的是英文符号 --> 导致接收到的size 和发送的size 大小不一致 3.注意同时定义两个槽函数的时候两个槽函数都会被调用&#xff0c;…

MySQL数据表的设计

实际工程中, 对于数据表的设计和创建, 我们遵循以下步骤: 首先确定实体, 找到关键名词, 提取关键信息, 设计表有哪些列, 每一列是什么. (有几个实体, 一般就创建几个表, 一般一个表对应一个实体) 实体之间的关系: 1. 一对一关系 例如: 一个学生, 只能有一个账号; 一个账号只…

基于单片机的病床呼叫系统设计研究

摘要&#xff1a;随着无线技术的快速发展&#xff0c;无线应用技术已经运用到人们生产生活中的多个领域&#xff0c;运用无线技术来设计病床呼叫系统能够实现无线信号的远距离传输&#xff0c;减少材料耗费&#xff0c;使医患之间的沟通更加便捷&#xff0c;该系统运用单片机作…

决定短视频打开率的要素:成都鼎茂宏升文化传媒公司

​ 在当下这个短视频盛行的时代&#xff0c;无论是个人创作者还是企业品牌&#xff0c;都希望通过短视频平台获得更多的曝光和关注。然而&#xff0c;如何让自己的短视频在众多内容中脱颖而出&#xff0c;吸引用户的点击和观看&#xff0c;成为了摆在我们面前的重要问题。成都…

nginx隐藏版本号、错误信息页面隐藏nginx软件、修改 HTTP 头信息中的connection 字段,防止回显具体版本号、curl命令

目录 安装之后隐藏 配置文件 源代码配置安装之前隐藏 修改nginx.h文件中的 13、14行 修改 HTTP 头信息中的connection 字段&#xff0c;防止回显具体版本号 配置文件49行 错误页面程序返回版本号、nginx隐藏 配置文件36行 ​编辑 安装nginx 相关选项说明 curl命令测试…

更新详情 | Flutter 3.22 与 Dart 3.4

作者 / Michael Thomsen 过去几个月&#xff0c;Dart & Flutter 部门可谓忙碌非凡&#xff0c;但我们很高兴地宣布&#xff0c;Flutter 3.22 和 Dart 3.4 已经在今年的 Google I/O 大会上精彩亮相&#xff01; Google I/Ohttps://io.google/2024/intl/zh/ 我们始终致力于提…

记一次mysql索引优化

生产日志告警出现一条慢 sql 告警, 通过 sql 监控平台拿到 这条sql 语句是 : SELECTid,report_id,report_detail_id,item_code,report_type,photo FROM**** 表 WHEREdel_flag 0 AND (report_type 1 AND report_detail_id IN ( 1742 )) 之后用 explain 分析这条 sql 的命中…

FPGA新起点V1开发板(九)——流水灯

文章目录 一、模块框图二、代码编写三、注意点四、总结 一、模块框图 二、代码编写 endmodule下面需要敲出一个回车代码拼接是大括号 led < {led[2:0],led[3]}注意二进制和十进制 module flow_led(input sys_clk50,input rst_n,output reg [3:0] le…

Java开发分析工具:JProfiler 14 for Mac/win 激活版下载

JProfiler是一款功能强大的Java应用程序性能分析工具&#xff0c;适用于Java开发人员和企业用户&#xff0c;可帮助他们识别和解决Java应用程序中的性能问题&#xff0c;提高应用程序的性能和稳定性。使用JProfiler&#xff0c;开发人员可以实时查看Java应用程序的性能数据&…

Redis数据类型(下篇)

5.Redis有序集合zset(sorted set) 本质就是在set的基础上&#xff0c;每个val值前面加了一个score分数值。 &#xff08;1&#xff09;向有序集合中添加多个&#xff08;或者一个&#xff09;元素和其对应的分数 127.0.0.1:6379> zadd zset1 100 a 90 b 80 c 70 d 60 e (…

【VMware虚拟机中ubuntu系列】—— 在虚拟机中使用本机摄像头的详细教程与常见问题分析及解决

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、虚拟机调用本机摄像头(1) 启动VMware USB 服务(2) 连接本机摄像头(3) 测试摄像头的连接 二、安装usb驱动二、运行usb_cam.launch时出现select timeout的报错…

vulhub中Nexus Repository Manager 3 未授权目录穿越漏洞(CVE-2024-4956)

Nexus Repository Manager 3 是一款软件仓库&#xff0c;可以用来存储和分发Maven、NuGET等软件源仓库。 其3.68.0及之前版本中&#xff0c;存在一处目录穿越漏洞。攻击者可以利用该漏洞读取服务器上任意文件。 环境启动后&#xff0c;访问http://your-ip:8081即可看到Nexus的…

npm发布、更新、删除包

如何将自己开发的依赖包发布到npmjs上供别人使用&#xff1f;五个步骤搞定&#xff01; 实现步骤&#xff1a; 创建自己的工具包项目&#xff0c;进行开发。注册npmjs账号。执行npm login在控制台登录&#xff0c;填写用户信息。执行npm publish发布包。更新及删除。 步骤一…

MongoDB~俩大特点管道聚合和数据压缩(snappy)

场景 在MySQL中&#xff0c;通常会涉及多个表的一些操作&#xff0c;MongoDB也类似&#xff0c;有时需要将多个文档甚至是多个集合汇总到一起计算分析&#xff08;比如求和、取最大值&#xff09;并返回计算后的结果&#xff0c;这个过程被称为 聚合操作 。 根据官方文档介绍&…