diff --git a/src/DjangoBlog-master/accounts/views.py b/src/DjangoBlog-master/accounts/views.py index ae67aec..5aceab3 100644 --- a/src/DjangoBlog-master/accounts/views.py +++ b/src/DjangoBlog-master/accounts/views.py @@ -32,25 +32,60 @@ logger = logging.getLogger(__name__) # Create your views here. class RegisterView(FormView): + """ + 用户注册视图类,继承自Django的FormView + 处理用户注册的全流程:表单展示、数据验证、用户创建、邮件发送 + """ + + #ZXY: 指定使用的表单类 form_class = RegisterForm + + #ZXY: 指定渲染的模板路径 template_name = 'account/registration_form.html' @method_decorator(csrf_protect) def dispatch(self, *args, **kwargs): + """ + 重写dispatch方法,添加CSRF保护装饰器 + CSRF保护:防止跨站请求伪造攻击,确保表单提交来自本站 + Returns: + HttpResponse: 处理后的HTTP响应 + """ return super(RegisterView, self).dispatch(*args, **kwargs) def form_valid(self, form): + """ + 表单数据验证成功后的处理逻辑 + 这是注册流程的核心方法,包含用户创建和邮件发送 + Args: + form: 已验证通过的RegisterForm实例 + Returns: + HttpResponseRedirect: 重定向到结果页面 + """ if form.is_valid(): + #ZXY: 第一步:创建用户对象但不立即保存到数据库 + #ZXY: save(False)表示只创建对象实例,不执行数据库INSERT user = form.save(False) - user.is_active = False - user.source = 'Register' + + #ZXY: 第二步:设置用户状态和属性 + user.is_active = False #ZXY: 邮箱验证前用户处于未激活状态,无法登录 + user.source = 'Register' #ZXY: 记录注册来源,便于后续统计分析 + + #ZXY: 第三步:保存用户到数据库 + #ZXY: save(True)表示立即执行数据库保存操作 user.save(True) - site = get_current_site().domain + + #ZXY: 第四步:准备邮箱验证所需数据 + site = get_current_site().domain #ZXY: 获取当前站点域名 + #ZXY: 生成安全签名:对密钥+用户ID进行双重SHA256哈希,防止篡改 sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) + #ZXY: 开发环境下使用本地地址,生产环境使用真实域名 if settings.DEBUG: - site = '127.0.0.1:8000' - path = reverse('account:result') + site = '127.0.0.1:8000' #ZXY: 开发环境固定地址 + + # 第五步:构建邮箱验证链接 + path = reverse('account:result') #ZXY: 生成结果页面的URL路径 url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format( site=site, path=path, id=user.id, sign=sign) @@ -64,141 +99,215 @@ class RegisterView(FormView): 如果上面链接无法打开,请将此链接复制至浏览器。 {url} """.format(url=url) + + #ZXY: 第七步:发送验证邮件 send_email( emailto=[ - user.email, + user.email, #ZXY: 收件人列表,这里只有注册用户 ], - title='验证您的电子邮箱', - content=content) + title='验证您的电子邮箱', #ZXY: 邮件标题 + content=content) #ZXY: 邮件正文内容 + #ZXY: 步骤8:重定向到注册结果页面 url = reverse('accounts:result') + \ '?type=register&id=' + str(user.id) return HttpResponseRedirect(url) else: + #ZXY: 表单验证失败,重新显示表单页 return self.render_to_response({ 'form': form }) class LogoutView(RedirectView): - url = '/login/' + """ + 用户退出登录视图 + 功能:处理用户退出,清除session,重定向到登录页 + """ + url = '/login/' #ZXY: 退出后重定向的URL - @method_decorator(never_cache) + @method_decorator(never_cache) #ZXY: 禁止缓存,确保每次都是最新状态 def dispatch(self, request, *args, **kwargs): return super(LogoutView, self).dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): - logout(request) - delete_sidebar_cache() + """ + 处理GET请求退出登录 + """ + logout(request) #ZXY: Django内置的退出函数,清除session + delete_sidebar_cache() #ZXY: 清除侧边栏缓存 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 # 一个月的时间 - - @method_decorator(sensitive_post_parameters('password')) - @method_decorator(csrf_protect) - @method_decorator(never_cache) + """ + 用户登录视图 + 功能:处理用户登录认证,支持"记住我"功能 + """ + form_class = LoginForm #ZXY: 登录表单 + template_name = 'account/login.html' #ZXY: 登录页面模板 + success_url = '/' #ZXY: 登录成功后的默认跳转页面 + redirect_field_name = REDIRECT_FIELD_NAME #ZXY: 重定向字段名,默认为'next' + login_ttl = 2626560 #ZXY: "记住我"功能的session有效期(一个月,单位:秒) + + @method_decorator(sensitive_post_parameters('password')) #ZXY: 敏感参数保护,不在错误报告中显示密码 + @method_decorator(csrf_protect) #ZXY: CSRF保护 + @method_decorator(never_cache) #ZXY: 禁止缓存 def dispatch(self, request, *args, **kwargs): - + """ + 添加安全装饰器的dispatch方法 + """ return super(LoginView, self).dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): + """ + 添加上下文数据,主要是重定向URL + """ redirect_to = self.request.GET.get(self.redirect_field_name) if redirect_to is None: - redirect_to = '/' + redirect_to = '/' #ZXY: 默认重定向到首页 kwargs['redirect_to'] = redirect_to return super(LoginView, self).get_context_data(**kwargs) def form_valid(self, form): + """ + 登录表单验证成功后的处理 + """ + #ZXY: 使用Django内置的AuthenticationForm进行认证 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() #ZXY: 清除侧边栏缓存 + logger.info(self.redirect_field_name) #ZXY: 记录日志 + #ZXY: 执行用户登录 auth.login(self.request, form.get_user()) + + #ZXY: 处理"记住我"功能 if self.request.POST.get("remember"): + #ZXY: 设置session过期时间为一个月 self.request.session.set_expiry(self.login_ttl) return super(LoginView, self).form_valid(form) - # return HttpResponseRedirect('/') + #ZXY: return HttpResponseRedirect('/') else: + #ZXY: 认证失败,重新显示表单 return self.render_to_response({ 'form': form }) def get_success_url(self): - + """ + 获取登录成功后的跳转URL + 支持next参数指定的重定向 + """ redirect_to = self.request.POST.get(self.redirect_field_name) + #ZXY: 安全检查:确保重定向URL在允许的host范围内 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 #ZXY: 不安全的URL使用默认首页 return redirect_to def account_result(request): - type = request.GET.get('type') - id = request.GET.get('id') + """ + 账户操作结果页面视图函数 + 处理注册结果和邮箱验证结果展示 + """ + type = request.GET.get('type') #ZXY: 操作类型:register或validation + id = request.GET.get('id') #ZXY: 用户ID + + + user = get_object_or_404(get_user_model(), id=id) #ZXY: 获取用户对象,不存在返回404 + logger.info(type) #ZXY: 记录操作类型日志 - user = get_object_or_404(get_user_model(), id=id) - logger.info(type) + #ZXY: 如果用户已激活,直接跳转到首页 if user.is_active: return HttpResponseRedirect('/') if type and type in ['register', 'validation']: if type == 'register': + #ZXY: 注册成功页面 content = ''' 恭喜您注册成功,一封验证邮件已经发送到您的邮箱,请验证您的邮箱后登录本站。 ''' title = '注册成功' else: + #ZXY: 邮箱验证处理 c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) sign = request.GET.get('sign') + + #ZXY: 签名验证,防止URL篡改 if sign != c_sign: - return HttpResponseForbidden() + return HttpResponseForbidden() #ZXY: 签名不匹配,返回403禁止访问 + + #ZXY: 激活用户账号 user.is_active = True user.save() content = ''' 恭喜您已经成功的完成邮箱验证,您现在可以使用您的账号来登录本站。 ''' title = '验证成功' + + #ZXY: 渲染结果页面 return render(request, 'account/result.html', { 'title': title, 'content': content }) else: + #ZXY: 无效的操作类型,跳转到首页 return HttpResponseRedirect('/') class ForgetPasswordView(FormView): - form_class = ForgetPasswordForm - template_name = 'account/forget_password.html' + """ + 忘记密码视图 + 功能:处理用户密码重置 + """ + form_class = ForgetPasswordForm #ZXY: 忘记密码表单 + template_name = 'account/forget_password.html' #ZXY: 模板路径 def form_valid(self, form): + """ + 表单验证成功后的密码重置逻辑 + """ if form.is_valid(): + #ZXY: 根据邮箱查找用户 blog_user = BlogUser.objects.filter(email=form.cleaned_data.get("email")).get() + + #ZXY: 使用Django的密码哈希函数设置新密码 blog_user.password = make_password(form.cleaned_data["new_password2"]) - blog_user.save() + blog_user.save() #ZXY: 保存到数据库 + + #ZXY: 重定向到登录页面 return HttpResponseRedirect('/login/') else: + #ZXY: 表单验证失败,重新显示表单 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("错误的邮箱") - to_email = form.cleaned_data["email"] + return HttpResponse("错误的邮箱") #ZXY: 表单验证失败 + to_email = form.cleaned_data["email"] #ZXY: 获取邮箱地址 + #ZXY: 生成6位验证码 code = generate_code() + + #ZXY: 发送验证码邮件 utils.send_verify_email(to_email, code) + + #ZXY: 将验证码存储到缓存(5分钟有效期) utils.set_code(to_email, code) - return HttpResponse("ok") + return HttpResponse("ok") #ZXY: 返回成功响应