djq注释 #40

Merged
phm9gvnzi merged 1 commits from djq_branch into master 3 months ago

@ -1,3 +1,14 @@
# -*- coding: utf-8 -*-
"""
# 模块级注释app: accounts
作者djq
功能用户账户相关视图逻辑包含用户注册登录登出密码找回及邮箱验证等功能
关联
- 表单RegisterForm注册表单LoginForm登录表单
- 模型BlogUser自定义用户模型
- 模板account/registration_form.html注册页account/login.html登录页
- 工具函数djangoblog.utils中的邮件发送加密等工具
"""
import logging
from django.utils.translation import gettext_lazy as _
from django.conf import settings
@ -32,28 +43,55 @@ logger = logging.getLogger(__name__)
# Create your views here.
class RegisterView(FormView):
form_class = RegisterForm
template_name = 'account/registration_form.html'
"""
功能处理用户注册逻辑包括表单验证创建未激活用户发送邮箱验证链接
继承FormViewDjango表单处理基类
核心流程
1. 验证注册表单数据
2. 创建用户并设置为未激活状态
3. 生成邮箱验证链接包含用户ID和加密签名
4. 发送验证邮件到用户邮箱
5. 重定向到注册结果页
"""
form_class = RegisterForm # 关联注册表单类
template_name = 'account/registration_form.html' # 注册页面模板
@method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
"""
功能重写dispatch方法添加CSRF保护装饰器防止跨站请求伪造
参数*args, **kwargs视图函数的位置参数和关键字参数
返回父类dispatch方法的处理结果
"""
return super(RegisterView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
"""
功能当表单验证通过后执行的逻辑核心注册流程
参数form验证通过的注册表单实例
返回重定向到注册结果页的响应
"""
if form.is_valid():
# djq: 创建用户但不立即保存(先设置额外属性)
user = form.save(False)
user.is_active = False
user.source = 'Register'
user.save(True)
user.is_active = False # djq: 新用户默认未激活(需邮箱验证)
user.source = 'Register' # djq: 标记用户来源为自主注册
user.save(True) # djq: 保存用户到数据库
# djq: 获取当前站点域名(用于构建验证链接)
site = get_current_site().domain
# djq: 生成加密签名结合SECRET_KEY和用户ID防止链接被篡改
sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
# djq: 开发环境下使用本地域名
if settings.DEBUG:
site = '127.0.0.1:8000'
path = reverse('account:result')
path = reverse('account:result') # djq: 验证结果页的路由
# djq: 拼接邮箱验证链接包含用户ID和签名
url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format(
site=site, path=path, id=user.id, sign=sign)
# djq: 验证邮件内容(包含验证链接)
content = """
<p>请点击下面链接验证您的邮箱</p>
@ -64,6 +102,7 @@ class RegisterView(FormView):
如果上面链接无法打开请将此链接复制至浏览器
{url}
""".format(url=url)
# djq: 发送验证邮件到用户注册邮箱
send_email(
emailto=[
user.email,
@ -71,134 +110,234 @@ class RegisterView(FormView):
title='验证您的电子邮箱',
content=content)
# djq: 重定向到注册结果页(提示用户查收验证邮件)
url = reverse('accounts:result') + \
'?type=register&id=' + str(user.id)
return HttpResponseRedirect(url)
else:
# djq: 表单验证失败时,返回原页面并显示错误
return self.render_to_response({
'form': form
})
class LogoutView(RedirectView):
url = '/login/'
"""
功能处理用户登出逻辑清除会话并跳转至登录页
继承RedirectViewDjango重定向基类
"""
url = '/login/' # 登出后跳转的目标URL登录页
@method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
"""
功能重写dispatch方法添加禁止缓存装饰器确保每次登出请求都是最新的
参数*args, **kwargs视图函数的参数
返回父类dispatch方法的处理结果
"""
return super(LogoutView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
logout(request)
delete_sidebar_cache()
"""
功能处理GET请求执行登出操作
参数requestHTTP请求对象
返回重定向到登录页的响应
"""
logout(request) # djq: 清除用户会话,完成登出
delete_sidebar_cache() # djq: 清除侧边栏缓存(可能包含用户相关信息)
return super(LogoutView, self).get(request, *args, **kwargs)
class LoginView(FormView):
form_class = LoginForm
template_name = 'account/login.html'
success_url = '/'
redirect_field_name = REDIRECT_FIELD_NAME
login_ttl = 2626560 # 一个月的时间
"""
功能处理用户登录逻辑包括表单验证用户认证会话管理
继承FormViewDjango表单处理基类
核心流程
1. 验证登录表单用户名/邮箱+密码
2. 认证用户身份
3. 根据"记住我"选项设置会话过期时间
4. 重定向到登录前的页面或首页
"""
form_class = LoginForm # 关联登录表单类
template_name = 'account/login.html' # 登录页面模板
success_url = '/' # 登录成功默认跳转页(首页)
redirect_field_name = REDIRECT_FIELD_NAME # 存储登录前URL的参数名
login_ttl = 2626560 # djq: 会话过期时间(单位:秒),此处为一个月
@method_decorator(sensitive_post_parameters('password'))
@method_decorator(csrf_protect)
@method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
"""
功能重写dispatch方法添加多重保护装饰器
- sensitive_post_parameters标记密码字段为敏感信息日志中隐藏
- csrf_protectCSRF保护
- never_cache禁止缓存
参数*args, **kwargs视图函数的参数
返回父类dispatch方法的处理结果
"""
return super(LoginView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
def get_context_data(self,** kwargs):
"""
功能向模板传递额外上下文数据登录前的跳转URL
参数**kwargs上下文关键字参数
返回包含跳转URL的上下文字典
"""
# djq: 获取登录前的页面URL从请求参数中提取
redirect_to = self.request.GET.get(self.redirect_field_name)
if redirect_to is None:
redirect_to = '/'
kwargs['redirect_to'] = redirect_to
redirect_to = '/' # djq: 默认跳转至首页
kwargs['redirect_to'] = redirect_to # djq: 将跳转URL添加到上下文
return super(LoginView, self).get_context_data(**kwargs)
return super(LoginView, self).get_context_data(** kwargs)
def form_valid(self, form):
"""
功能表单验证通过后执行的登录逻辑
参数form验证通过的登录表单实例
返回重定向到目标页面的响应
"""
# djq: 使用Django内置认证表单再次验证兼容用户名/邮箱登录)
form = AuthenticationForm(data=self.request.POST, request=self.request)
if form.is_valid():
delete_sidebar_cache()
logger.info(self.redirect_field_name)
delete_sidebar_cache() # djq: 清除侧边栏缓存(更新用户登录状态)
logger.info(self.redirect_field_name) # djq: 记录跳转参数名到日志
# djq: 执行登录(将用户信息存入会话)
auth.login(self.request, form.get_user())
# djq: 如果勾选"记住我",设置会话过期时间为一个月
if self.request.POST.get("remember"):
self.request.session.set_expiry(self.login_ttl)
return super(LoginView, self).form_valid(form)
# return HttpResponseRedirect('/')
else:
# djq: 表单验证失败(如密码错误),返回原页面显示错误
return self.render_to_response({
'form': form
})
def get_success_url(self):
"""
功能确定登录成功后的跳转URL优先跳转到登录前的页面
返回安全的跳转URL
"""
# djq: 从POST参数中获取登录前的URL
redirect_to = self.request.POST.get(self.redirect_field_name)
# djq: 验证跳转URL是否安全防止跳转到外部恶意网站
if not url_has_allowed_host_and_scheme(
url=redirect_to, allowed_hosts=[
self.request.get_host()]):
redirect_to = self.success_url
redirect_to = self.success_url # djq: 不安全则使用默认首页
return redirect_to
def account_result(request):
type = request.GET.get('type')
id = request.GET.get('id')
"""
功能处理注册结果和邮箱验证结果的展示
参数requestHTTP请求对象
返回渲染结果页面的响应
逻辑
1. 区分"注册成功""邮箱验证成功"两种场景
2. 验证场景合法性如验证链接的签名是否有效
3. 展示对应结果信息
"""
type = request.GET.get('type') # djq: 获取场景类型register/validation
id = request.GET.get('id') # djq: 获取用户ID
# djq: 获取对应的用户不存在则返回404
user = get_object_or_404(get_user_model(), id=id)
logger.info(type)
logger.info(type) # djq: 记录场景类型到日志
# djq: 如果用户已激活,直接跳转至首页(避免重复验证)
if user.is_active:
return HttpResponseRedirect('/')
if type and type in ['register', 'validation']:
if type == 'register':
# djq: 注册成功场景:提示用户查收验证邮件
content = '''
恭喜您注册成功一封验证邮件已经发送到您的邮箱请验证您的邮箱后登录本站
'''
title = '注册成功'
else:
c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
sign = request.GET.get('sign')
# djq: 邮箱验证场景:验证签名合法性
c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) # 计算正确签名
sign = request.GET.get('sign') # 获取请求中的签名
if sign != c_sign:
return HttpResponseForbidden()
return HttpResponseForbidden() # djq: 签名不匹配返回403禁止访问
# djq: 签名验证通过,激活用户
user.is_active = True
user.save()
# djq: 提示用户验证成功
content = '''
恭喜您已经成功的完成邮箱验证您现在可以使用您的账号来登录本站
'''
title = '验证成功'
# djq: 渲染结果页面
return render(request, 'account/result.html', {
'title': title,
'content': content
})
else:
# djq: 场景类型不合法,跳转至首页
return HttpResponseRedirect('/')
class ForgetPasswordView(FormView):
form_class = ForgetPasswordForm
template_name = 'account/forget_password.html'
"""
功能处理密码找回逻辑通过邮箱验证后重置密码
继承FormViewDjango表单处理基类
"""
form_class = ForgetPasswordForm # 关联密码找回表单
template_name = 'account/forget_password.html' # 密码找回页面模板
def form_valid(self, form):
"""
功能表单验证通过后执行的密码重置逻辑
参数form验证通过的密码找回表单实例
返回重定向到登录页的响应
"""
if form.is_valid():
# djq: 根据邮箱获取用户(假设表单已验证邮箱存在)
blog_user = BlogUser.objects.filter(email=form.cleaned_data.get("email")).get()
# djq: 加密新密码并保存make_password自动处理哈希
blog_user.password = make_password(form.cleaned_data["new_password2"])
blog_user.save()
# djq: 密码重置成功,跳转至登录页
return HttpResponseRedirect('/login/')
else:
# djq: 表单验证失败(如密码不一致),返回原页面
return self.render_to_response({'form': form})
class ForgetPasswordEmailCode(View):
"""
功能处理密码找回时的邮箱验证码发送逻辑
继承ViewDjango基础视图类
核心流程
1. 验证邮箱格式
2. 生成随机验证码
3. 发送验证码到目标邮箱
4. 存储验证码用于后续验证
"""
def post(self, request: HttpRequest):
"""
功能处理POST请求发送密码找回验证码
参数requestHTTP请求对象包含邮箱参数
返回"ok"字符串成功或错误提示
"""
# djq: 验证请求中的邮箱格式
form = ForgetPasswordCodeForm(request.POST)
if not form.is_valid():
return HttpResponse("错误的邮箱")
to_email = form.cleaned_data["email"]
return HttpResponse("错误的邮箱") # djq: 邮箱格式错误,返回提示
to_email = form.cleaned_data["email"] # djq: 获取验证通过的邮箱
code = generate_code()
utils.send_verify_email(to_email, code)
utils.set_code(to_email, code)
code = generate_code() # djq: 生成随机验证码
utils.send_verify_email(to_email, code) # djq: 发送验证码到邮箱
utils.set_code(to_email, code) # djq: 存储验证码(如存入缓存,用于后续校验)
return HttpResponse("ok")
return HttpResponse("ok") # djq: 发送成功,返回标识
Loading…
Cancel
Save