From 5854b4eab4b31c99e76c24e39b570415a657fe86 Mon Sep 17 00:00:00 2001 From: lunhun <2077786863@qq.com> Date: Sun, 12 Oct 2025 23:18:12 +0800 Subject: [PATCH] =?UTF-8?q?account:=20=E8=A1=A5=E5=85=85=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/forms.py | 39 +++++++++--- accounts/views.py | 155 +++++++++++++++++++++++++--------------------- 2 files changed, 114 insertions(+), 80 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index fce4137..39c9aa2 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -8,19 +8,26 @@ from . import utils from .models import BlogUser +# ------------------------- 登录表单 ------------------------- class LoginForm(AuthenticationForm): + """登录表单类(继承 Django 内置 AuthenticationForm)""" + 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 自带 UserCreationForm)""" + 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( @@ -31,17 +38,23 @@ class RegisterForm(UserCreationForm): attrs={'placeholder': "repeat password", "class": "form-control"}) def clean_email(self): + """检查邮箱是否已被注册""" email = self.cleaned_data['email'] if get_user_model().objects.filter(email=email).exists(): - raise ValidationError(_("email already exists")) + raise ValidationError(_("email already exists")) # 抛出重复邮箱异常 return email class Meta: + """指定绑定的模型和表单字段""" model = get_user_model() fields = ("username", "email") +# ------------------------- 忘记密码表单 ------------------------- class ForgetPasswordForm(forms.Form): + """用户通过邮箱重置密码的表单""" + + # 新密码输入 new_password1 = forms.CharField( label=_("New password"), widget=forms.PasswordInput( @@ -52,6 +65,7 @@ class ForgetPasswordForm(forms.Form): ), ) + # 新密码确认输入 new_password2 = forms.CharField( label="确认密码", widget=forms.PasswordInput( @@ -62,6 +76,7 @@ class ForgetPasswordForm(forms.Form): ), ) + # 邮箱输入 email = forms.EmailField( label='邮箱', widget=forms.TextInput( @@ -72,6 +87,7 @@ class ForgetPasswordForm(forms.Form): ), ) + # 验证码输入 code = forms.CharField( label=_('Code'), widget=forms.TextInput( @@ -82,36 +98,39 @@ class ForgetPasswordForm(forms.Form): ), ) + # ----------- 字段验证逻辑 ----------- def clean_new_password2(self): + """验证两次输入的新密码是否一致,并校验密码强度""" 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) - + raise ValidationError(_("passwords do not match")) # 两次密码不一致 + password_validation.validate_password(password2) # 使用Django内置规则验证密码强度 return password2 def clean_email(self): + """验证邮箱是否存在于数据库""" 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(): + # 这里可以根据项目安全策略决定是否提示“邮箱不存在” raise ValidationError(_("email does not exist")) return user_email def clean_code(self): + """验证邮箱验证码是否正确或过期""" code = self.cleaned_data.get("code") error = utils.verify( email=self.cleaned_data.get("email"), code=code, ) - if error: + if error: # utils.verify 返回错误信息时表示验证失败 raise ValidationError(error) return code +# ------------------------- 验证码邮箱发送表单 ------------------------- class ForgetPasswordCodeForm(forms.Form): + """发送邮箱验证码表单,仅校验邮箱格式""" email = forms.EmailField( label=_('Email'), ) diff --git a/accounts/views.py b/accounts/views.py index ae67aec..390e1ee 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -7,11 +7,9 @@ from django.contrib.auth import get_user_model from django.contrib.auth import logout from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.hashers import make_password -from django.http import HttpResponseRedirect, HttpResponseForbidden +from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse from django.http.request import HttpRequest -from django.http.response import HttpResponse -from django.shortcuts import get_object_or_404 -from django.shortcuts import render +from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.utils.decorators import method_decorator from django.utils.http import url_has_allowed_host_and_scheme @@ -26,147 +24,159 @@ from . import utils from .forms import RegisterForm, LoginForm, ForgetPasswordForm, ForgetPasswordCodeForm from .models import BlogUser -logger = logging.getLogger(__name__) +logger = logging.getLogger(__name__) # 初始化日志记录器 -# Create your views here. - +# ------------------------- 注册视图 ------------------------- class RegisterView(FormView): + """用户注册视图""" form_class = RegisterForm - template_name = 'account/registration_form.html' + template_name = 'account/registration_form.html' # 注册页面模板路径 - @method_decorator(csrf_protect) + @method_decorator(csrf_protect) # 防止CSRF攻击 def dispatch(self, *args, **kwargs): 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) - site = get_current_site().domain - sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) - - if settings.DEBUG: + user = form.save(False) # 保存用户但不提交数据库 + 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 = """ -
请点击下面链接验证您的邮箱
- - {url} - - 再次感谢您! -请点击下面链接验证您的邮箱
+ {url} + 再次感谢您! +