|
|
|
|
@ -1,59 +1,84 @@
|
|
|
|
|
#shw 导入日志模块
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
#shw 导入Django的认证模块
|
|
|
|
|
from django.contrib import auth
|
|
|
|
|
#shw 导入登录后重定向字段的常量名
|
|
|
|
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
|
|
|
|
#shw 导入获取用户模型的函数
|
|
|
|
|
from django.contrib.auth import get_user_model
|
|
|
|
|
#shw 导入登出函数
|
|
|
|
|
from django.contrib.auth import logout
|
|
|
|
|
#shw 导入Django内置的认证表单
|
|
|
|
|
from django.contrib.auth.forms import AuthenticationForm
|
|
|
|
|
#shw 导入密码哈希生成函数
|
|
|
|
|
from django.contrib.auth.hashers import make_password
|
|
|
|
|
#shw 导入HTTP响应相关类
|
|
|
|
|
from django.http import HttpResponseRedirect, HttpResponseForbidden
|
|
|
|
|
from django.http.request import HttpRequest
|
|
|
|
|
from django.http.response import HttpResponse
|
|
|
|
|
#shw 导入Django的快捷函数
|
|
|
|
|
from django.shortcuts import get_object_or_404
|
|
|
|
|
from django.shortcuts import render
|
|
|
|
|
#shw 导入URL反向解析函数
|
|
|
|
|
from django.urls import reverse
|
|
|
|
|
#shw 导入方法装饰器
|
|
|
|
|
from django.utils.decorators import method_decorator
|
|
|
|
|
#shw 导入URL安全检查函数
|
|
|
|
|
from django.utils.http import url_has_allowed_host_and_scheme
|
|
|
|
|
#shw 导入Django的视图基类
|
|
|
|
|
from django.views import View
|
|
|
|
|
from django.views.decorators.cache import never_cache
|
|
|
|
|
from django.views.decorators.csrf import csrf_protect
|
|
|
|
|
from django.views.decorators.debug import sensitive_post_parameters
|
|
|
|
|
from django.views.generic import FormView, RedirectView
|
|
|
|
|
|
|
|
|
|
#shw 从项目工具模块导入所需函数
|
|
|
|
|
from djangoblog.utils import send_email, get_sha256, get_current_site, generate_code, delete_sidebar_cache
|
|
|
|
|
#shw 导入本地的工具模块和表单
|
|
|
|
|
from . import utils
|
|
|
|
|
from .forms import RegisterForm, LoginForm, ForgetPasswordForm, ForgetPasswordCodeForm
|
|
|
|
|
#shw 导入本地的模型
|
|
|
|
|
from .models import BlogUser
|
|
|
|
|
|
|
|
|
|
#shw 获取当前模块的日志记录器
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create your views here.
|
|
|
|
|
#shw 在这里创建你的视图。
|
|
|
|
|
|
|
|
|
|
class RegisterView(FormView):
|
|
|
|
|
form_class = RegisterForm
|
|
|
|
|
template_name = 'account/registration_form.html'
|
|
|
|
|
#shw 用户注册视图,继承自FormView,用于处理用户注册逻辑。
|
|
|
|
|
form_class = RegisterForm #shw 指定使用的表单类
|
|
|
|
|
template_name = 'account/registration_form.html' #shw 指定渲染的模板
|
|
|
|
|
|
|
|
|
|
@method_decorator(csrf_protect)
|
|
|
|
|
def dispatch(self, *args, **kwargs):
|
|
|
|
|
#shw 为视图的dispatch方法添加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)
|
|
|
|
|
site = get_current_site().domain
|
|
|
|
|
#shw 当表单验证通过时执行此方法
|
|
|
|
|
if form.is_valid(): #shw 再次确认表单有效
|
|
|
|
|
user = form.save(False) #shw 保存表单数据,但先不提交到数据库(commit=False)
|
|
|
|
|
user.is_active = False #shw 将用户状态设为未激活,需要邮箱验证
|
|
|
|
|
user.source = 'Register' #shw 设置用户来源为注册
|
|
|
|
|
user.save(True) #shw 现在将用户对象保存到数据库
|
|
|
|
|
|
|
|
|
|
site = get_current_site().domain #shw 获取当前站点域名
|
|
|
|
|
#shw 生成用于邮箱验证的双重哈希签名
|
|
|
|
|
sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
|
|
|
|
|
|
|
|
|
|
#shw 如果是调试模式,则使用本地地址
|
|
|
|
|
if settings.DEBUG:
|
|
|
|
|
site = '127.0.0.1:8000'
|
|
|
|
|
path = reverse('account:result')
|
|
|
|
|
path = reverse('account:result') #shw 获取结果页面的URL路径
|
|
|
|
|
#shw 构造完整的邮箱验证链接
|
|
|
|
|
url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format(
|
|
|
|
|
site=site, path=path, id=user.id, sign=sign)
|
|
|
|
|
|
|
|
|
|
#shw 构造邮件内容
|
|
|
|
|
content = """
|
|
|
|
|
<p>请点击下面链接验证您的邮箱</p>
|
|
|
|
|
|
|
|
|
|
@ -64,6 +89,7 @@ class RegisterView(FormView):
|
|
|
|
|
如果上面链接无法打开,请将此链接复制至浏览器。
|
|
|
|
|
{url}
|
|
|
|
|
""".format(url=url)
|
|
|
|
|
#shw 发送验证邮件
|
|
|
|
|
send_email(
|
|
|
|
|
emailto=[
|
|
|
|
|
user.email,
|
|
|
|
|
@ -71,135 +97,159 @@ class RegisterView(FormView):
|
|
|
|
|
title='验证您的电子邮箱',
|
|
|
|
|
content=content)
|
|
|
|
|
|
|
|
|
|
#shw 构造注册成功后的跳转URL,提示用户去查收邮件
|
|
|
|
|
url = reverse('accounts:result') + \
|
|
|
|
|
'?type=register&id=' + str(user.id)
|
|
|
|
|
return HttpResponseRedirect(url)
|
|
|
|
|
return HttpResponseRedirect(url) #shw 重定向到结果页面
|
|
|
|
|
else:
|
|
|
|
|
#shw 如果表单无效,重新渲染注册页面并显示错误
|
|
|
|
|
return self.render_to_response({
|
|
|
|
|
'form': form
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LogoutView(RedirectView):
|
|
|
|
|
url = '/login/'
|
|
|
|
|
#shw 用户登出视图,继承自RedirectView,用于处理用户登出逻辑。
|
|
|
|
|
url = '/login/' #shw 登出后重定向的URL
|
|
|
|
|
|
|
|
|
|
@method_decorator(never_cache)
|
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
|
#shw 为视图添加never_cache装饰器,确保该页面不被缓存
|
|
|
|
|
return super(LogoutView, self).dispatch(request, *args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
|
logout(request)
|
|
|
|
|
delete_sidebar_cache()
|
|
|
|
|
return super(LogoutView, self).get(request, *args, **kwargs)
|
|
|
|
|
logout(request) #shw 调用Django的logout函数,清除session信息
|
|
|
|
|
delete_sidebar_cache() #shw 删除侧边栏缓存
|
|
|
|
|
return super(LogoutView, self).get(request, *args, **kwargs) #shw 执行重定向
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LoginView(FormView):
|
|
|
|
|
form_class = LoginForm
|
|
|
|
|
template_name = 'account/login.html'
|
|
|
|
|
success_url = '/'
|
|
|
|
|
redirect_field_name = REDIRECT_FIELD_NAME
|
|
|
|
|
login_ttl = 2626560 # 一个月的时间
|
|
|
|
|
#shw 用户登录视图,继承自FormView,用于处理用户登录逻辑。
|
|
|
|
|
form_class = LoginForm #shw 指定使用的表单类
|
|
|
|
|
template_name = 'account/login.html' #shw 指定渲染的模板
|
|
|
|
|
success_url = '/' #shw 登录成功后默认的重定向URL
|
|
|
|
|
redirect_field_name = REDIRECT_FIELD_NAME #shw 指定包含重定向URL的GET参数名
|
|
|
|
|
login_ttl = 2626560 # 一个月的时间(秒),用于“记住我”功能的session过期时间
|
|
|
|
|
|
|
|
|
|
@method_decorator(sensitive_post_parameters('password'))
|
|
|
|
|
@method_decorator(csrf_protect)
|
|
|
|
|
@method_decorator(never_cache)
|
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
|
|
|
|
|
|
#shw 为视图添加多个装饰器:保护密码参数、CSRF保护、禁止缓存
|
|
|
|
|
return super(LoginView, self).dispatch(request, *args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
|
redirect_to = self.request.GET.get(self.redirect_field_name)
|
|
|
|
|
#shw 向模板上下文中添加额外的数据
|
|
|
|
|
redirect_to = self.request.GET.get(self.redirect_field_name) #shw 获取GET参数中的重定向URL
|
|
|
|
|
if redirect_to is None:
|
|
|
|
|
redirect_to = '/'
|
|
|
|
|
kwargs['redirect_to'] = redirect_to
|
|
|
|
|
redirect_to = '/' #shw 如果没有,则默认为根路径
|
|
|
|
|
kwargs['redirect_to'] = redirect_to #shw 将重定向URL添加到上下文
|
|
|
|
|
|
|
|
|
|
return super(LoginView, self).get_context_data(**kwargs)
|
|
|
|
|
|
|
|
|
|
def form_valid(self, form):
|
|
|
|
|
#shw 当表单验证通过时执行此方法
|
|
|
|
|
#shw 使用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() #shw 删除侧边栏缓存
|
|
|
|
|
logger.info(self.redirect_field_name) #shw 记录日志
|
|
|
|
|
|
|
|
|
|
auth.login(self.request, form.get_user())
|
|
|
|
|
auth.login(self.request, form.get_user()) #shw 调用Django的login函数,将用户信息存入session
|
|
|
|
|
#shw 如果用户勾选了“记住我”
|
|
|
|
|
if self.request.POST.get("remember"):
|
|
|
|
|
self.request.session.set_expiry(self.login_ttl)
|
|
|
|
|
return super(LoginView, self).form_valid(form)
|
|
|
|
|
# return HttpResponseRedirect('/')
|
|
|
|
|
self.request.session.set_expiry(self.login_ttl) #shw 设置session的过期时间为一个月
|
|
|
|
|
return super(LoginView, self).form_valid(form) #shw 调用父类方法,处理重定向
|
|
|
|
|
else:
|
|
|
|
|
#shw 如果验证失败,重新渲染登录页面并显示错误
|
|
|
|
|
return self.render_to_response({
|
|
|
|
|
'form': form
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
def get_success_url(self):
|
|
|
|
|
|
|
|
|
|
redirect_to = self.request.POST.get(self.redirect_field_name)
|
|
|
|
|
#shw 获取登录成功后应重定向的URL
|
|
|
|
|
redirect_to = self.request.POST.get(self.redirect_field_name) #shw 从POST数据中获取重定向URL
|
|
|
|
|
#shw 检查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 #shw 如果URL不安全,则使用默认的success_url
|
|
|
|
|
return redirect_to
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def account_result(request):
|
|
|
|
|
type = request.GET.get('type')
|
|
|
|
|
id = request.GET.get('id')
|
|
|
|
|
#shw 函数视图,用于处理注册和邮箱验证的结果展示。
|
|
|
|
|
type = request.GET.get('type') #shw 获取URL参数中的类型
|
|
|
|
|
id = request.GET.get('id') #shw 获取URL参数中的用户ID
|
|
|
|
|
|
|
|
|
|
user = get_object_or_404(get_user_model(), id=id)
|
|
|
|
|
logger.info(type)
|
|
|
|
|
if user.is_active:
|
|
|
|
|
user = get_object_or_404(get_user_model(), id=id) #shw 根据ID获取用户对象,如果不存在则返回404
|
|
|
|
|
logger.info(type) #shw 记录日志
|
|
|
|
|
if user.is_active: #shw 如果用户已经激活,则直接跳转到首页
|
|
|
|
|
return HttpResponseRedirect('/')
|
|
|
|
|
#shw 处理两种类型:注册成功提示和邮箱验证
|
|
|
|
|
if type and type in ['register', 'validation']:
|
|
|
|
|
if type == 'register':
|
|
|
|
|
#shw 如果是注册类型,显示注册成功、请查收邮件的提示
|
|
|
|
|
content = '''
|
|
|
|
|
恭喜您注册成功,一封验证邮件已经发送到您的邮箱,请验证您的邮箱后登录本站。
|
|
|
|
|
'''
|
|
|
|
|
title = '注册成功'
|
|
|
|
|
else:
|
|
|
|
|
c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
|
|
|
|
|
sign = request.GET.get('sign')
|
|
|
|
|
if sign != c_sign:
|
|
|
|
|
#shw 如果是验证类型,需要验证签名
|
|
|
|
|
c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) #shw 重新计算正确的签名
|
|
|
|
|
sign = request.GET.get('sign') #shw 获取URL中的签名
|
|
|
|
|
if sign != c_sign: #shw 比较签名,如果不一致则返回403禁止访问
|
|
|
|
|
return HttpResponseForbidden()
|
|
|
|
|
user.is_active = True
|
|
|
|
|
user.save()
|
|
|
|
|
user.is_active = True #shw 激活用户
|
|
|
|
|
user.save() #shw 保存用户状态
|
|
|
|
|
#shw 显示验证成功的提示
|
|
|
|
|
content = '''
|
|
|
|
|
恭喜您已经成功的完成邮箱验证,您现在可以使用您的账号来登录本站。
|
|
|
|
|
'''
|
|
|
|
|
title = '验证成功'
|
|
|
|
|
#shw 渲染结果页面
|
|
|
|
|
return render(request, 'account/result.html', {
|
|
|
|
|
'title': title,
|
|
|
|
|
'content': content
|
|
|
|
|
})
|
|
|
|
|
else:
|
|
|
|
|
#shw 如果类型不匹配,则跳转到首页
|
|
|
|
|
return HttpResponseRedirect('/')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForgetPasswordView(FormView):
|
|
|
|
|
form_class = ForgetPasswordForm
|
|
|
|
|
template_name = 'account/forget_password.html'
|
|
|
|
|
#shw 忘记密码视图,用于处理通过验证码重置密码的逻辑。
|
|
|
|
|
form_class = ForgetPasswordForm #shw 指定使用的表单
|
|
|
|
|
template_name = 'account/forget_password.html' #shw 指定渲染的模板
|
|
|
|
|
|
|
|
|
|
def form_valid(self, form):
|
|
|
|
|
if form.is_valid():
|
|
|
|
|
#shw 当表单验证通过时执行此方法
|
|
|
|
|
if form.is_valid(): #shw 再次确认表单有效
|
|
|
|
|
#shw 根据邮箱获取用户对象
|
|
|
|
|
blog_user = BlogUser.objects.filter(email=form.cleaned_data.get("email")).get()
|
|
|
|
|
#shw 使用make_password对新密码进行哈希处理
|
|
|
|
|
blog_user.password = make_password(form.cleaned_data["new_password2"])
|
|
|
|
|
blog_user.save()
|
|
|
|
|
return HttpResponseRedirect('/login/')
|
|
|
|
|
blog_user.save() #shw 保存用户的新密码
|
|
|
|
|
return HttpResponseRedirect('/login/') #shw 重定向到登录页面
|
|
|
|
|
else:
|
|
|
|
|
#shw 如果表单无效,重新渲染页面并显示错误
|
|
|
|
|
return self.render_to_response({'form': form})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForgetPasswordEmailCode(View):
|
|
|
|
|
|
|
|
|
|
#shw 发送忘记密码验证码的视图,继承自基础的View。
|
|
|
|
|
@staticmethod
|
|
|
|
|
def post(request: HttpRequest):
|
|
|
|
|
form = ForgetPasswordCodeForm(request.POST)
|
|
|
|
|
if not form.is_valid():
|
|
|
|
|
return HttpResponse("错误的邮箱")
|
|
|
|
|
to_email = form.cleaned_data["email"]
|
|
|
|
|
#shw 只处理POST请求
|
|
|
|
|
form = ForgetPasswordCodeForm(request.POST) #shw 用POST数据实例化表单
|
|
|
|
|
if not form.is_valid(): #shw 验证表单(主要是验证邮箱格式)
|
|
|
|
|
return HttpResponse("错误的邮箱") #shw 如果无效,返回错误信息
|
|
|
|
|
to_email = form.cleaned_data["email"] #shw 获取清洗后的邮箱
|
|
|
|
|
|
|
|
|
|
code = generate_code()
|
|
|
|
|
utils.send_verify_email(to_email, code)
|
|
|
|
|
utils.set_code(to_email, code)
|
|
|
|
|
code = generate_code() #shw 生成一个验证码
|
|
|
|
|
utils.send_verify_email(to_email, code) #shw 调用工具函数发送验证邮件
|
|
|
|
|
utils.set_code(to_email, code) #shw 调用工具函数将验证码存入缓存
|
|
|
|
|
|
|
|
|
|
return HttpResponse("ok")
|
|
|
|
|
return HttpResponse("ok") #shw 返回成功信息
|
|
|
|
|
|