基于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 forms

class 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 SetPasswordForm

class 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, PasswordResetConfirmView

urlpatterns = [
    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,发动密码重置链接到邮箱地址。发送成功,如下:

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

重置密码成功,如下:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

量产导入 | 芯片测试介绍可靠性测试

作者:桃芯科技链接:https://picture.iczhiku.com/weixin/message1583129221975.html半导体芯片的defects、Faults 芯片在制造过程中,会出现很多种不同类型的defects,比如栅氧层针孔、扩散工艺造成的各种桥接、各种预期外的高阻态、寄生电容电阻造成的延迟等等,如下面图(1)…

Spring高手之路19——Spring AOP注解指南

文章目录 1. 背景2. 基于AspectJ注解来实现AOP3. XML实现和注解实现AOP的代码对比4. AOP通知讲解5. AOP时序图 1. 背景 在现代软件开发中&#xff0c;面向切面编程&#xff08;AOP&#xff09;是一种强大的编程范式&#xff0c;允许开发者跨越应用程序的多个部分定义横切关注点…

数据隐私重塑:Web3时代的隐私保护创新

随着数字化时代的不断深入&#xff0c;数据隐私保护已经成为了人们越来越关注的焦点之一。而在这个数字化时代的新篇章中&#xff0c;Web3技术作为下一代互联网的代表&#xff0c;正在为数据隐私保护带来全新的创新和可能性。本文将深入探讨数据隐私的重要性&#xff0c;Web3时…

解锁数据宝藏:高效查找算法揭秘

代码下载链接&#xff1a;https://gitee.com/flying-wolf-loves-learning/data-structure.git 目录 一、查找的原理 1.1 查找概念 1.2 查找方法 1.3平均查找长度 1.4顺序表的查找 1.5 顺序表的查找算法及分析 1.6 折半查找算法及分析 1.7 分块查找算法及分析 1.8 总结…

很多人讲不明白HTTPS,但是我能

很多人讲不明白HTTPS&#xff0c;但是我能 今天我们用问答的形式&#xff0c;来彻底弄明白HTTPS的过程 下面的问题都是 小明和小丽两个人通信为例 可以把小明想象成服务端&#xff0c;小丽想象成客户端 1. https是做什么用的&#xff1f; 答&#xff1a;数据安全传输用的。…

数学建模 —— 聚类分析(3)

目录 一、聚类分析概述 1.1 常用聚类要素的数据处理 1.1.1 总和标准化 1.1.2 标准差标准化 1.1.3 极大值标准化 1.1.4 极差的标准化 1.2 分类 1.2.1 快速聚类法&#xff08;K-均值聚类&#xff09; 1.2.2 系统聚类法&#xff08;分层聚类法&#xff09; 二、分类统计…

Ubuntu18.04安装pwntools报错解决方案

报错1&#xff1a;ModuleNotFoundError: No module named ‘setuptools_rust’ 报错信息显示ModuleNotFoundError: No module named setuptools_rust&#xff0c;如下图所示 解决方案&#xff1a;pip install setuptools_rust 报错2&#xff1a;pip版本低 解决方案&#xff…

【数据结构(邓俊辉)学习笔记】图02——搜索

文章目录 0. 概述1. 广度优先搜索1.1 策略1.2 实现1.3 可能情况1.4 实例1.5 多联通1.6 复杂度1.7 最短路径 2. 深度优先搜索2.1 算法2.2 框架2.3 细节2.4 无向边2.5 有向边2.6 多可达域2.7 嵌套引理 3 遍历算法的应用 0. 概述 此前已经介绍过图的基本概念以及它在计算机中的表…

设计模式(十四)行为型模式---访问者模式(visitor)

文章目录 访问者模式简介分派的分类什么是双分派&#xff1f;结构UML图具体实现UML图代码实现 优缺点 访问者模式简介 访问者模式&#xff08;visitor pattern&#xff09;是封装一些作用于某种数据结构中的元素的操作&#xff0c;它可以在不改变这个数据结构&#xff08;实现…

Visual Studio Installer 点击闪退

Visual Studio Installer 点击闪退问题 1. 问题描述2. 错误类型3. 解决方法4. 结果5. 说明6. 参考 1. 问题描述 重装了系统后&#xff08;系统版本&#xff1a;如下图所示&#xff09;&#xff0c;我从官方网站&#xff08;https://visualstudio.microsoft.com/ ) 下载了安装程…

Three.js-实现加载图片并旋转

1.实现效果 2. 实现步骤 2.1创建场景 const scene new THREE.Scene(); 2.2添加相机 说明&#xff1a; fov&#xff08;视场角&#xff09;&#xff1a;视场角决定了相机的视野范围&#xff0c;即相机可以看到的角度范围。较大的视场角表示更广阔的视野&#xff0c;但可能…

如何在镜像中安装固定版本的node和npm

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、使用 Dockerfile 创建自定义镜像二、如何安装固定版本的node及npm总结 前言 最近在做前端工程化相关的内容&#xff0c;需要在一个镜像内安装固定版本的 N…

Microservices with Martin Fowler

Summary The article “Microservices” by Martin Fowler discusses an architectural style for software systems that has been gaining popularity due to its flexibility and scalability. Here’s a summary highlighting the key points: Microservice Architectural…

十_信号4-SIGCHLD信号

SIGCHLD信号 在学习进程控制的时候&#xff0c;使用wait和waitpid系统调用何以回收僵尸进程&#xff0c;父进程可以阻塞等待&#xff0c;也可以非阻塞等待&#xff0c;采用轮询的方式不停查询子进程是否退出。 采用阻塞式等待&#xff0c;父进程就被阻塞了&#xff0c;什么都干…

【魅力网页的背后】:CSS基础魔法,从零打造视觉盛宴

文章目录 &#x1f680;一、css基础知识⭐1. 认识css &#x1f308;二、选择器初级❤️id与class命名 &#x1f680;一、css基础知识 ⭐1. 认识css 概念 CSS(英文全称&#xff1a;Cascading Style Sheets)&#xff0c;层叠样式表。它是网页的装饰者&#xff0c;用来修饰各标签…

YOLOv5改进(六)--引入YOLOv8中C2F模块

文章目录 1、前言2、C3模块和C2F模块2.1、C3模块2.2、BottleNeck模块2.3、C2F模块 3、C2F代码实现3.1、common.py3.2、yolo.py3.3、yolov5s_C2F.yaml 4、目标检测系列文章 1、前言 本文主要使用YOLOv8的C2F模块替换YOLOv5中的C3模块&#xff0c;经过实验测试&#xff0c;发现Y…

深圳雷龙LSYT201B语音控制模组

文章目录 前言一、芯片简介处理器外设音频蓝牙电源封装温度 二、功能简介管脚描述 三、应用场景四、使用说明五、硬件连接六、FAQ总结 前言 今天拿到的语音控制板是LSYT201B模组&#xff0c;它是深圳市雷龙发展有限公司基于YT2228芯片开发的一款面向智能家居控制的离线语音控制…

SSM高校社团管理系统-计算机毕业设计源码86128

目 录 摘要 1 绪论 1.1研究背景与意义 1.2开发现状 1.3研究方法 1.4 ssm框架介绍 1.5论文结构与章节安排 2 高校社团管理系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1数据增加流程 2.2.2数据修改流程 2.2.3数据删除流程 2.3 系统功能分析 2.3.1 功能性分…

大模型部署_书生浦语大模型 _作业2基本demo

本节课可以让同学们实践 4 个主要内容&#xff0c;分别是&#xff1a; 1、部署 InternLM2-Chat-1.8B 模型进行智能对话 1.1安装依赖库&#xff1a; pip install huggingface-hub0.17.3 pip install transformers4.34 pip install psutil5.9.8 pip install accelerate0.24.1…

类和对象(一)(C++)

类和对象&#xff1a; 类的引入&#xff1a; C语言结构体中只能定义变量&#xff0c;在C中&#xff0c;结构体内不仅可以定义变量&#xff0c;也可以定义函数。比如&#xff1a; 之前在数据结构初阶中&#xff0c;用C语言方式实现的栈&#xff0c;结构体中只能定义变量&#…