From 009e363737b4128245e676db0ac9a41590fa61ca Mon Sep 17 00:00:00 2001 From: hyt <691385292@qq.com> Date: Sun, 9 Nov 2025 20:27:01 +0800 Subject: [PATCH] =?UTF-8?q?hyt=5Faccounts=20APP=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/accounts/admin.py | 76 ++----------- src/accounts/apps.py | 19 +--- src/accounts/forms.py | 107 ++---------------- src/accounts/models.py | 54 +-------- src/accounts/urls.py | 62 ++++------- src/accounts/user_login_backend.py | 53 +-------- src/accounts/utils.py | 68 +++--------- src/accounts/views.py | 170 +++++------------------------ 8 files changed, 95 insertions(+), 514 deletions(-) diff --git a/src/accounts/admin.py b/src/accounts/admin.py index d2ef475..32e483c 100644 --- a/src/accounts/admin.py +++ b/src/accounts/admin.py @@ -1,5 +1,3 @@ -#hyt: - from django import forms from django.contrib.auth.admin import UserAdmin from django.contrib.auth.forms import UserChangeForm @@ -11,33 +9,15 @@ from .models import BlogUser class BlogUserCreationForm(forms.ModelForm): - """ - 博客用户创建表单 - - 用于管理员后台创建新用户,提供密码验证和哈希处理功能 - 扩展了 Django 原生用户创建逻辑,支持自定义字段和来源标记 - """ - password1 = forms.CharField(label=_('password'), widget=forms.PasswordInput) password2 = forms.CharField(label=_('Enter password again'), widget=forms.PasswordInput) class Meta: model = BlogUser - fields = ('email',) # 创建用户时只要求填写邮箱字段 + fields = ('email',) def clean_password2(self): - """ - 密码确认验证 - - 检查两次输入的密码是否一致 - 确保用户在创建账户时正确确认密码 - - 返回: - 验证通过的密码 - - 异常: - ValidationError: 当两次密码不匹配时抛出 - """ + # Check that the two password entries match password1 = self.cleaned_data.get("password1") password2 = self.cleaned_data.get("password2") if password1 and password2 and password1 != password2: @@ -45,60 +25,28 @@ class BlogUserCreationForm(forms.ModelForm): return password2 def save(self, commit=True): - """ - 保存用户信息 - - 重写保存方法,对密码进行哈希处理并标记用户来源 - - 参数: - commit: 是否立即保存到数据库 - - 返回: - 保存后的用户对象 - """ - # 保存提供的密码为哈希格式 + # Save the provided password in hashed format user = super().save(commit=False) user.set_password(self.cleaned_data["password1"]) if commit: - user.source = 'adminsite' # 标记用户来源为管理员后台 + user.source = 'adminsite' user.save() return user class BlogUserChangeForm(UserChangeForm): - """ - 博客用户信息修改表单 - - 用于管理员后台编辑现有用户信息 - 继承 Django 原生用户修改表单,支持所有字段编辑 - """ - class Meta: model = BlogUser - fields = '__all__' # 包含所有模型字段 - field_classes = {'username': UsernameField} # 用户名字段使用特定字段类 + fields = '__all__' + field_classes = {'username': UsernameField} def __init__(self, *args, **kwargs): - """ - 初始化表单 - - 调用父类初始化方法,可在此处添加自定义初始化逻辑 - """ super().__init__(*args, **kwargs) class BlogUserAdmin(UserAdmin): - """ - 博客用户管理后台配置 - - 自定义用户模型在 Django Admin 后台的显示和编辑配置 - 扩展了默认的用户管理功能,添加了自定义字段显示 - """ - - form = BlogUserChangeForm # 用户编辑表单 - add_form = BlogUserCreationForm # 用户创建表单 - - # 列表页面显示的字段 + form = BlogUserChangeForm + add_form = BlogUserCreationForm list_display = ( 'id', 'nickname', @@ -106,8 +54,6 @@ class BlogUserAdmin(UserAdmin): 'email', 'last_login', 'date_joined', - 'source' - ) - - list_display_links = ('id', 'username') # 可点击链接的字段 - ordering = ('-id',) # 按 ID 降序排列 \ No newline at end of file + 'source') + list_display_links = ('id', 'username') + ordering = ('-id',) diff --git a/src/accounts/apps.py b/src/accounts/apps.py index 2148ee0..9b3fc5a 100644 --- a/src/accounts/apps.py +++ b/src/accounts/apps.py @@ -1,20 +1,5 @@ -#hyt: - from django.apps import AppConfig -class AccountsConfig(AppConfig): - """ - 账户管理应用配置类 - - 负责配置 accounts 应用在 Django 项目中的行为 - 包括应用名称、初始化逻辑、信号注册等配置项 - 功能特性: - - 用户认证和权限管理 - - 用户资料管理 - - 登录注册功能 - - 会话管理 - """ - - # 应用路径标识 - Django 用于识别应用的完整 Python 路径 - name = 'accounts' \ No newline at end of file +class AccountsConfig(AppConfig): + name = 'accounts' diff --git a/src/accounts/forms.py b/src/accounts/forms.py index f68134e..fce4137 100644 --- a/src/accounts/forms.py +++ b/src/accounts/forms.py @@ -1,5 +1,3 @@ -#hyt: - from django import forms from django.contrib.auth import get_user_model, password_validation from django.contrib.auth.forms import AuthenticationForm, UserCreationForm @@ -11,45 +9,18 @@ from .models import BlogUser class LoginForm(AuthenticationForm): - """ - 用户登录表单 - - 继承 Django 原生认证表单,自定义界面样式和占位符文本 - 提供用户名和密码的登录验证功能 - """ - def __init__(self, *args, **kwargs): - """ - 初始化表单控件 - - 设置表单字段的样式类和占位符文本,优化用户体验 - """ super(LoginForm, self).__init__(*args, **kwargs) - # 设置用户名字段的输入框样式 self.fields['username'].widget = widgets.TextInput( attrs={'placeholder': "username", "class": "form-control"}) - # 设置密码字段的输入框样式 self.fields['password'].widget = widgets.PasswordInput( attrs={'placeholder': "password", "class": "form-control"}) class RegisterForm(UserCreationForm): - """ - 用户注册表单 - - 处理新用户注册流程,包括用户名、邮箱验证和密码确认 - 扩展了 Django 原生用户创建表单,添加邮箱字段和样式定制 - """ - def __init__(self, *args, **kwargs): - """ - 初始化注册表单控件 - - 为所有表单字段设置统一的样式类和占位符提示 - """ super(RegisterForm, self).__init__(*args, **kwargs) - # 设置各字段的输入框样式和占位符 self.fields['username'].widget = widgets.TextInput( attrs={'placeholder': "username", "class": "form-control"}) self.fields['email'].widget = widgets.EmailInput( @@ -60,37 +31,17 @@ class RegisterForm(UserCreationForm): attrs={'placeholder': "repeat password", "class": "form-control"}) def clean_email(self): - """ - 邮箱唯一性验证 - - 检查邮箱是否已被其他用户注册,确保邮箱地址的唯一性 - - 返回: - 验证通过的邮箱地址 - - 异常: - ValidationError: 当邮箱已存在时抛出 - """ email = self.cleaned_data['email'] if get_user_model().objects.filter(email=email).exists(): raise ValidationError(_("email already exists")) return email class Meta: - """表单元数据配置""" - model = get_user_model() # 使用当前激活的用户模型 - fields = ("username", "email") # 注册时需要填写的字段 + model = get_user_model() + fields = ("username", "email") class ForgetPasswordForm(forms.Form): - """ - 密码重置表单 - - 处理用户忘记密码时的重置流程,包含邮箱验证、验证码校验和新密码设置 - 通过多步骤验证确保账户安全 - """ - - # 新密码字段 - 第一次输入 new_password1 = forms.CharField( label=_("New password"), widget=forms.PasswordInput( @@ -101,7 +52,6 @@ class ForgetPasswordForm(forms.Form): ), ) - # 新密码字段 - 确认输入 new_password2 = forms.CharField( label="确认密码", widget=forms.PasswordInput( @@ -112,7 +62,6 @@ class ForgetPasswordForm(forms.Form): ), ) - # 邮箱字段 - 用于身份验证 email = forms.EmailField( label='邮箱', widget=forms.TextInput( @@ -123,7 +72,6 @@ class ForgetPasswordForm(forms.Form): ), ) - # 验证码字段 - 安全验证 code = forms.CharField( label=_('Code'), widget=forms.TextInput( @@ -135,57 +83,24 @@ class ForgetPasswordForm(forms.Form): ) def clean_new_password2(self): - """ - 新密码确认验证 - - 检查两次输入的新密码是否一致,并验证密码强度 - - 返回: - 验证通过的密码 - - 异常: - ValidationError: 当密码不匹配或强度不足时抛出 - """ password1 = self.data.get("new_password1") password2 = self.data.get("new_password2") - # 检查密码是否匹配 if password1 and password2 and password1 != password2: raise ValidationError(_("passwords do not match")) - # 验证密码强度 password_validation.validate_password(password2) return password2 def clean_email(self): - """ - 邮箱存在性验证 - - 验证输入的邮箱是否在系统中已注册 - - 返回: - 验证通过的邮箱地址 - - 异常: - ValidationError: 当邮箱不存在时抛出 - """ user_email = self.cleaned_data.get("email") - if not BlogUser.objects.filter(email=user_email).exists(): - # TODO: 这里的报错提示可以判断一个邮箱是不是注册过,如果不想暴露可以修改 + if not BlogUser.objects.filter( + email=user_email + ).exists(): + # todo 这里的报错提示可以判断一个邮箱是不是注册过,如果不想暴露可以修改 raise ValidationError(_("email does not exist")) return user_email def clean_code(self): - """ - 验证码校验 - - 验证邮箱和验证码的匹配关系,确保重置请求的合法性 - - 返回: - 验证通过的验证码 - - 异常: - ValidationError: 当验证码无效时抛出 - """ code = self.cleaned_data.get("code") error = utils.verify( email=self.cleaned_data.get("email"), @@ -197,14 +112,6 @@ class ForgetPasswordForm(forms.Form): class ForgetPasswordCodeForm(forms.Form): - """ - 密码重置验证码请求表单 - - 用于请求发送密码重置验证码,只需提供邮箱地址 - 是密码重置流程的第一步 - """ - - # 邮箱字段 - 用于发送验证码 email = forms.EmailField( label=_('Email'), - ) \ No newline at end of file + ) diff --git a/src/accounts/models.py b/src/accounts/models.py index 33769bd..3baddbb 100644 --- a/src/accounts/models.py +++ b/src/accounts/models.py @@ -1,5 +1,3 @@ -#hyt: - from django.contrib.auth.models import AbstractUser from django.db import models from django.urls import reverse @@ -11,71 +9,27 @@ from djangoblog.utils import get_current_site # Create your models here. class BlogUser(AbstractUser): - """ - 博客用户模型 - - 扩展 Django 内置 AbstractUser 模型,添加博客系统特有的用户字段 - 支持用户昵称、时间戳跟踪和来源标识等功能 - """ - - # 昵称字段 - 用户显示名称,可为空 nickname = models.CharField(_('nick name'), max_length=100, blank=True) - - # 创建时间 - 用户账户创建的时间戳 creation_time = models.DateTimeField(_('creation time'), default=now) - - # 最后修改时间 - 用户信息最后更新的时间戳 last_modify_time = models.DateTimeField(_('last modify time'), default=now) - - # 来源标识 - 用户注册来源(如网站、管理员创建等) source = models.CharField(_('create source'), max_length=100, blank=True) def get_absolute_url(self): - """ - 获取用户详情页的绝对URL - - 用于生成用户个人主页的链接,支持反向解析 - - 返回: - 用户详情页的URL路径 - """ return reverse( 'blog:author_detail', kwargs={ 'author_name': self.username}) def __str__(self): - """ - 对象字符串表示 - - 在Admin后台和Shell中显示用户的邮箱地址 - - 返回: - 用户的邮箱地址 - """ return self.email def get_full_url(self): - """ - 获取用户的完整URL(包含域名) - - 生成包含协议和域名的完整用户主页链接 - - 返回: - 用户的完整主页URL - """ site = get_current_site().domain url = "https://{site}{path}".format(site=site, path=self.get_absolute_url()) return url class Meta: - """ - 模型元数据配置 - - 定义模型在数据库和Admin后台中的行为 - """ - - ordering = ['-id'] # 默认按ID降序排列 - verbose_name = _('user') # 单数显示名称 - verbose_name_plural = verbose_name # 复数显示名称(与单数相同) - get_latest_by = 'id' # 获取最新记录的依据字段 \ No newline at end of file + ordering = ['-id'] + verbose_name = _('user') + verbose_name_plural = verbose_name + get_latest_by = 'id' diff --git a/src/accounts/urls.py b/src/accounts/urls.py index d6c0d54..107a801 100644 --- a/src/accounts/urls.py +++ b/src/accounts/urls.py @@ -1,50 +1,28 @@ -#hyt: - from django.urls import path from django.urls import re_path from . import views from .forms import LoginForm -# 应用命名空间 - 用于URL反向解析时区分不同应用的URL app_name = "accounts" -# URL模式配置 - 定义账户管理相关的所有路由规则 -urlpatterns = [ - # 用户登录路由 - # 使用正则表达式匹配 /login/ 路径 - re_path(r'^login/$', - views.LoginView.as_view(success_url='/'), # 登录成功后跳转到首页 - name='login', # URL名称,用于反向解析 - kwargs={'authentication_form': LoginForm}), # 传入自定义登录表单 - - # 用户注册路由 - # 使用正则表达式匹配 /register/ 路径 - re_path(r'^register/$', - views.RegisterView.as_view(success_url="/"), # 注册成功后跳转到首页 - name='register'), # URL名称,用于反向解析 - - # 用户退出登录路由 - # 使用正则表达式匹配 /logout/ 路径 - re_path(r'^logout/$', - views.LogoutView.as_view(), # 使用Django内置的退出视图 - name='logout'), # URL名称,用于反向解析 - - # 账户操作结果页面路由 - # 使用path匹配固定路径 /account/result.html - path(r'account/result.html', - views.account_result, # 函数视图,显示账户操作结果 - name='result'), # URL名称,用于反向解析 - - # 忘记密码页面路由 - # 使用正则表达式匹配 /forget_password/ 路径 - re_path(r'^forget_password/$', - views.ForgetPasswordView.as_view(), # 类视图,处理密码重置 - name='forget_password'), # URL名称,用于反向解析 - - # 忘记密码验证码请求路由 - # 使用正则表达式匹配 /forget_password_code/ 路径 - re_path(r'^forget_password_code/$', - views.ForgetPasswordEmailCode.as_view(), # 类视图,发送验证码 - name='forget_password_code'), # URL名称,用于反向解析 -] \ No newline at end of file +urlpatterns = [re_path(r'^login/$', + views.LoginView.as_view(success_url='/'), + name='login', + kwargs={'authentication_form': LoginForm}), + re_path(r'^register/$', + views.RegisterView.as_view(success_url="/"), + name='register'), + re_path(r'^logout/$', + views.LogoutView.as_view(), + name='logout'), + path(r'account/result.html', + views.account_result, + name='result'), + re_path(r'^forget_password/$', + views.ForgetPasswordView.as_view(), + name='forget_password'), + re_path(r'^forget_password_code/$', + views.ForgetPasswordEmailCode.as_view(), + name='forget_password_code'), + ] diff --git a/src/accounts/user_login_backend.py b/src/accounts/user_login_backend.py index c851bd0..73cdca1 100644 --- a/src/accounts/user_login_backend.py +++ b/src/accounts/user_login_backend.py @@ -1,67 +1,26 @@ -#hyt: - from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend class EmailOrUsernameModelBackend(ModelBackend): """ - 自定义认证后端 - 支持邮箱或用户名登录 - - 扩展 Django 原生认证系统,允许用户使用用户名或邮箱地址进行登录 - 提供更灵活的用户认证方式,提升用户体验 + 允许使用用户名或邮箱登录 """ def authenticate(self, request, username=None, password=None, **kwargs): - """ - 用户认证方法 - - 根据输入的用户名判断是邮箱还是用户名,并进行相应的认证处理 - 支持两种登录方式: - - 用户名登录:username = "admin" - - 邮箱登录:username = "admin@example.com" - - 参数: - request: HttpRequest 对象 - username: 用户输入的用户名或邮箱地址 - password: 用户输入的密码 - **kwargs: 其他关键字参数 - - 返回: - User 对象: 认证成功时返回用户对象 - None: 认证失败时返回 None - """ - # 根据输入内容判断是邮箱还是用户名 if '@' in username: - kwargs = {'email': username} # 按邮箱查询 + kwargs = {'email': username} else: - kwargs = {'username': username} # 按用户名查询 - + kwargs = {'username': username} try: - # 根据查询条件获取用户对象 user = get_user_model().objects.get(**kwargs) - # 验证密码是否正确 if user.check_password(password): return user except get_user_model().DoesNotExist: - # 用户不存在时返回 None return None - def get_user(self, user_id): - """ - 根据用户ID获取用户对象 - - 用于会话认证期间从用户ID获取用户对象 - 保持与 Django 原生认证后端的兼容性 - - 参数: - user_id: 用户的主键ID - - 返回: - User 对象: 用户存在时返回用户对象 - None: 用户不存在时返回 None - """ + def get_user(self, username): try: - return get_user_model().objects.get(pk=user_id) + return get_user_model().objects.get(pk=username) except get_user_model().DoesNotExist: - return None \ No newline at end of file + return None diff --git a/src/accounts/utils.py b/src/accounts/utils.py index 265471f..4b94bdf 100644 --- a/src/accounts/utils.py +++ b/src/accounts/utils.py @@ -1,5 +1,3 @@ -#hyt: - import typing from datetime import timedelta @@ -9,21 +7,15 @@ from django.utils.translation import gettext_lazy as _ from djangoblog.utils import send_email -# 验证码有效期配置 - 5分钟过期时间 _code_ttl = timedelta(minutes=5) def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email")): - """ - 发送邮箱验证邮件 - - 用于密码重置、邮箱验证等场景,向指定邮箱发送包含验证码的邮件 - 邮件内容支持国际化,验证码有效期为5分钟 - - 参数: - to_mail: 接收邮件的邮箱地址 - code: 需要发送的验证码 - subject: 邮件主题,默认为"Verify Email" + """发送重设密码验证码 + Args: + to_mail: 接受邮箱 + subject: 邮件主题 + code: 验证码 """ html_content = _( "You are resetting the password, the verification code is:%(code)s, valid within 5 minutes, please keep it " @@ -32,23 +24,15 @@ def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email")) def verify(email: str, code: str) -> typing.Optional[str]: - """ - 验证验证码是否有效 - - 检查用户输入的验证码与缓存中的验证码是否匹配 - 用于验证邮箱验证码的正确性 - - 参数: - email: 请求验证的邮箱地址 - code: 用户输入的验证码 - - 返回: - str: 验证失败时返回错误信息 - None: 验证成功时返回None - - 注意: - 这里的错误处理不太合理,应该采用raise抛出异常 - 否则调用方也需要对error进行处理,增加了调用复杂度 + """验证code是否有效 + Args: + email: 请求邮箱 + code: 验证码 + Return: + 如果有错误就返回错误str + Node: + 这里的错误处理不太合理,应该采用raise抛出 + 否测调用方也需要对error进行处理 """ cache_code = get_code(email) if cache_code != code: @@ -56,30 +40,10 @@ def verify(email: str, code: str) -> typing.Optional[str]: def set_code(email: str, code: str): - """ - 设置验证码到缓存 - - 将验证码与邮箱关联并存储到缓存中,设置5分钟的有效期 - - 参数: - email: 邮箱地址,作为缓存的键 - code: 验证码,作为缓存的值 - """ + """设置code""" cache.set(email, code, _code_ttl.seconds) def get_code(email: str) -> typing.Optional[str]: - """ - 从缓存获取验证码 - - 根据邮箱地址从缓存中获取对应的验证码 - 如果验证码不存在或已过期,返回None - - 参数: - email: 邮箱地址,作为缓存的键 - - 返回: - str: 找到的验证码 - None: 验证码不存在或已过期 - """ + """获取code""" return cache.get(email) diff --git a/src/accounts/views.py b/src/accounts/views.py index 87e1714..ae67aec 100644 --- a/src/accounts/views.py +++ b/src/accounts/views.py @@ -1,5 +1,3 @@ -#hyt: - import logging from django.utils.translation import gettext_lazy as _ from django.conf import settings @@ -28,57 +26,34 @@ from . import utils from .forms import RegisterForm, LoginForm, ForgetPasswordForm, ForgetPasswordCodeForm from .models import BlogUser -# 日志记录器 logger = logging.getLogger(__name__) # Create your views here. class RegisterView(FormView): - """ - 用户注册视图 - - 处理新用户注册流程,包括表单验证、用户创建和邮箱验证邮件发送 - 注册后用户处于未激活状态,需要邮箱验证后才能登录 - """ - form_class = RegisterForm # 注册表单类 - template_name = 'account/registration_form.html' # 注册页面模板 + form_class = RegisterForm + template_name = 'account/registration_form.html' @method_decorator(csrf_protect) def dispatch(self, *args, **kwargs): - """ - 请求分发方法 - - 添加CSRF保护装饰器,防止跨站请求伪造攻击 - """ return super(RegisterView, self).dispatch(*args, **kwargs) def form_valid(self, form): - """ - 表单验证通过处理 - - 保存用户信息,发送邮箱验证邮件,跳转到结果页面 - """ if form.is_valid(): - # 保存用户信息但不立即提交到数据库 user = form.save(False) - user.is_active = False # 设置用户为未激活状态 - user.source = 'Register' # 标记用户来源为注册 - user.save(True) # 保存到数据库 - - # 生成邮箱验证链接 + user.is_active = False + user.source = 'Register' + user.save(True) site = get_current_site().domain sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) - # 开发环境下使用本地地址 if settings.DEBUG: site = '127.0.0.1:8000' - path = reverse('account:result') url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format( site=site, path=path, id=user.id, sign=sign) - # 构建邮件内容 content = """

请点击下面链接验证您的邮箱

@@ -89,7 +64,6 @@ class RegisterView(FormView): 如果上面链接无法打开,请将此链接复制至浏览器。 {url} """.format(url=url) - # 发送验证邮件 send_email( emailto=[ user.email, @@ -97,220 +71,134 @@ class RegisterView(FormView): title='验证您的电子邮箱', content=content) - # 跳转到注册结果页面 url = reverse('accounts:result') + \ '?type=register&id=' + str(user.id) return HttpResponseRedirect(url) else: - # 表单验证失败,重新渲染表单页面 return self.render_to_response({ 'form': form }) class LogoutView(RedirectView): - """ - 用户退出登录视图 - - 处理用户退出登录流程,清理会话和缓存,重定向到登录页面 - """ - url = '/login/' # 退出后重定向的URL + url = '/login/' @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): - """ - 请求分发方法 - - 添加不缓存装饰器,确保退出后页面不被缓存 - """ return super(LogoutView, self).dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): - """ - GET请求处理 - - 执行退出登录操作,清理用户会话和侧边栏缓存 - """ - logout(request) # Django内置退出登录方法 - delete_sidebar_cache() # 清理侧边栏缓存 + logout(request) + delete_sidebar_cache() return super(LogoutView, self).get(request, *args, **kwargs) class LoginView(FormView): - """ - 用户登录视图 - - 处理用户登录认证,支持记住登录状态和重定向功能 - """ - form_class = LoginForm # 登录表单类 - template_name = 'account/login.html' # 登录页面模板 - success_url = '/' # 登录成功默认跳转URL - redirect_field_name = REDIRECT_FIELD_NAME # 重定向字段名 - login_ttl = 2626560 # 记住登录状态的会话有效期(一个月) - - @method_decorator(sensitive_post_parameters('password')) # 保护密码参数 - @method_decorator(csrf_protect) # CSRF保护 - @method_decorator(never_cache) # 禁止缓存 + form_class = LoginForm + template_name = 'account/login.html' + success_url = '/' + redirect_field_name = REDIRECT_FIELD_NAME + login_ttl = 2626560 # 一个月的时间 + + @method_decorator(sensitive_post_parameters('password')) + @method_decorator(csrf_protect) + @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): - """ - 请求分发方法 - 添加安全相关的装饰器,保护登录过程的安全性 - """ return super(LoginView, self).dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): - """ - 获取模板上下文数据 - - 处理重定向参数,确保登录后能正确跳转 - """ redirect_to = self.request.GET.get(self.redirect_field_name) if redirect_to is None: - redirect_to = '/' # 默认重定向到首页 + redirect_to = '/' kwargs['redirect_to'] = redirect_to return super(LoginView, self).get_context_data(**kwargs) def form_valid(self, form): - """ - 表单验证通过处理 - - 执行用户登录认证,处理记住登录状态选项 - """ form = AuthenticationForm(data=self.request.POST, request=self.request) if form.is_valid(): - # 登录成功,清理缓存并记录日志 delete_sidebar_cache() logger.info(self.redirect_field_name) - # 执行登录操作 auth.login(self.request, form.get_user()) - - # 处理"记住我"选项 if self.request.POST.get("remember"): - self.request.session.set_expiry(self.login_ttl) # 设置会话有效期 + self.request.session.set_expiry(self.login_ttl) return super(LoginView, self).form_valid(form) + # return HttpResponseRedirect('/') else: - # 登录失败,重新显示表单 return self.render_to_response({ 'form': form }) def get_success_url(self): - """ - 获取登录成功后的跳转URL - 验证重定向URL的安全性,防止开放重定向攻击 - """ redirect_to = self.request.POST.get(self.redirect_field_name) - # 验证重定向URL是否安全 if not url_has_allowed_host_and_scheme( url=redirect_to, allowed_hosts=[ self.request.get_host()]): - redirect_to = self.success_url # 不安全则使用默认URL + redirect_to = self.success_url return redirect_to def account_result(request): - """ - 账户操作结果页面视图 - - 显示注册成功或邮箱验证成功的结果信息 - 处理邮箱验证链接的验证逻辑 - """ - type = request.GET.get('type') # 操作类型:register或validation - id = request.GET.get('id') # 用户ID + type = request.GET.get('type') + id = request.GET.get('id') user = get_object_or_404(get_user_model(), id=id) logger.info(type) - - # 如果用户已激活,直接跳转到首页 if user.is_active: return HttpResponseRedirect('/') - - # 处理注册结果或邮箱验证 if type and type in ['register', 'validation']: if type == 'register': - # 注册成功页面 content = ''' 恭喜您注册成功,一封验证邮件已经发送到您的邮箱,请验证您的邮箱后登录本站。 ''' title = '注册成功' else: - # 邮箱验证处理 c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) sign = request.GET.get('sign') - # 验证签名防止篡改 if sign != c_sign: return HttpResponseForbidden() - # 激活用户账户 user.is_active = True user.save() content = ''' 恭喜您已经成功的完成邮箱验证,您现在可以使用您的账号来登录本站。 ''' title = '验证成功' - # 渲染结果页面 return render(request, 'account/result.html', { 'title': title, 'content': content }) else: - # 无效的操作类型,跳转到首页 return HttpResponseRedirect('/') class ForgetPasswordView(FormView): - """ - 忘记密码重置视图 - - 处理用户忘记密码后的密码重置流程 - 验证验证码后更新用户密码 - """ - form_class = ForgetPasswordForm # 忘记密码表单 - template_name = 'account/forget_password.html' # 模板路径 + form_class = ForgetPasswordForm + template_name = 'account/forget_password.html' def form_valid(self, form): - """ - 表单验证通过处理 - - 重置用户密码并重定向到登录页面 - """ if form.is_valid(): - # 获取用户并更新密码 blog_user = BlogUser.objects.filter(email=form.cleaned_data.get("email")).get() - blog_user.password = make_password(form.cleaned_data["new_password2"]) # 哈希密码 + blog_user.password = make_password(form.cleaned_data["new_password2"]) blog_user.save() - return HttpResponseRedirect('/login/') # 重定向到登录页面 + return HttpResponseRedirect('/login/') else: - # 表单验证失败,重新显示表单 return self.render_to_response({'form': form}) class ForgetPasswordEmailCode(View): - """ - 忘记密码验证码发送视图 - - 处理忘记密码流程中的验证码发送请求 - """ def post(self, request: HttpRequest): - """ - POST请求处理 - - 验证邮箱地址并发送密码重置验证码 - """ form = ForgetPasswordCodeForm(request.POST) if not form.is_valid(): - return HttpResponse("错误的邮箱") # 邮箱格式错误 - + return HttpResponse("错误的邮箱") to_email = form.cleaned_data["email"] - # 生成并发送验证码 code = generate_code() utils.send_verify_email(to_email, code) utils.set_code(to_email, code) - return HttpResponse("ok") # 发送成功 \ No newline at end of file + return HttpResponse("ok")