以在首页判断当前是否为登录状态为例,分别使用三种方式作对比:
第一种是直接在视图函数中判断ticket(cookie中产生的随机值)是否存在,是否能在服务端(session)中找到对应的user对象。
def index(request):
if request.method == 'GET':
# 获取ticket
ticket = request.COOKIES.get('ticket')
# 通过ticket去user_ticket表中取数据
user_ticket = UserTicket.objects.filter(ticket=ticket).first()
if user_ticket:
# 获取当前用户
user = user_ticket.user
return render(request, 'index.html', {'user': user})
else:
return HttpResponseRedirect(reverse('users:login'))
最容易理解的一种方法,但局限性很大,若一个工程中页面很多的时候,判断是否登录状态使用这种方法代码量先不说,重复的次数过多,会使整个逻辑复杂化。所以一般情况下是不使用。
第二种是使用闭包(装饰器 )
闭包需要满足的三个基本条件:
a)外部函数中内嵌函数
b)内嵌函数调用外部函数的参数
c)外部函数返回内嵌函数
def is_login(func):
def check(request):
ticket = request.COOKIES.get('ticket')
if ticket:
# 通过user_ticket获取对象
user_ticket = UserTicket.objects.filter(ticket=ticket).first()
if user_ticket:
return func(request)
else:
# ticket参数错误,则跳转到登录界面重新登录
return HttpResponseRedirect(reverse('users:login'))
else:
# 无登录状态,返回登录界面
return HttpResponseRedirect(reverse('users:login'))
return check
闭包使用的两种方法
1)在需要判断的视图函数前添加装饰器(有点面向切面的感觉)
视图函数前判断
2)在路由引入前添加装饰器
引入路由时判断
第三种是使用中间件
重构process_request()方法,排除不需要验证的地址。设置全局的user,request,user默认为AnnoyMousUser。
import datetime
from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponseRedirect
from django.urls import reverse
from users.models import UserTicket
class UserMiddleware(MiddlewareMixin):
# 重构拦截方法
def process_request(self, request):
# 排除不需要登录验证的地址
not_login_path = ['/users/login/', '/users/register/']
path = request.path
# 校验不需要验证的地址
for n_path in not_login_path:
# 如果当前访问的地址未登录地址或注册地址,则返回None直接访问视图函数
if path == n_path:
return None
ticket = request.COOKIES.get('ticket')
# 如果请求的cookie中没有ticket,则跳转到登录
if not ticket:
return HttpResponseRedirect(reverse('users:login'))
# 删除user_ticket表中,时间超过了1000s的记录
user_tickets = UserTicket.objects.all()
user_tickets.update(max_age=datetime.now())
for user in user_tickets:
times = datetime.timestamp(user.create_time) + 1000000 - datetime.timestamp(user.max_age)
if times < 0:
user.delete()
# 通过ticket参数获取当前登录系统的用户信息
user_ticket = UserTicket.objects.filter(ticket=ticket).first()
if not user_ticket:
return HttpResponseRedirect(reverse('users:login'))
# 设置全局的user
request.user = user_ticket.user
# 中间件执行结束,可返回None或者不写
return None