一. 登录/注册/登录状态权限验证
前言
通过cookie和token去实现登录功能,用户在登录账号以后,随机产生一个随机数并存在cookie中,并在服务端也存储同一个数在数据库中。当下一次url请求过来的时候,解析request中绑定的cookie信息,解锁出之前存的随机数,判断该随机数是否是存储在服务器端的数据,如果没有查询到则表示该cookie过期,或者该cookie是伪造的,或者服务器上存储该信息的数据缓存到期被清空了。则该提示用户重新登录,并且重新产生随机数,并存储在cookie中以及服务端,以保证下次请求和响应能够顺利。
练手题目
题目:
1) 编写一个方法,用于注册用户的账号和密码。
2) 编写一个方法,用于登录用户的账号和密码,并且登录的时候绑定一个加密的参数在cookie上,并且该加密参数也存储在服务端中。
3)在以后的任意一个请求,我们都获取request中的cookies,查看cookie中绑定的参数是否合法,以及查询是否在服务端存储了。
4)如果验证成功则返回请求url的结果信息到页面,如果验证失败则返回错误提醒信息页面
5) 注销登录
6)定义装饰器去验证用户登录以后才执行对应的视图函数,反之跳转到登录页面中
1. 注册方法
从页面中获取账号和密码,进行创建
2. 登录,并且绑定参数到cookie上
先检验用户名是否在数据库中,如果查询到则继续验证密码, 如果密码验证对,则绑定一个参数到cookie中。
解析密码,加密密码来源与一下的模块:
from django.contrib.auth.hashers import check_password, make_password
3. 在方法中验证cookie中传递的参数是否正确
cookie是在用户提交url请求的时候都会带上的一个参数,所以可以从中获取到我们设置的参数,并且在服务端进行验证,看服务端有这个标识符没有,
如果能查询到,则表示用户登录过了,并且还在登录时效内,则直接返回用户提交url对应的响应。如果在服务端没有查询到数据,则表示标识符过期,
或者无效了,需要登录了,则直接提示错误信息即可!
4. 注销登录
删除cookie中的认证令牌
5. 通过定义装饰器去验证用户是否是登录状态,如果不是,则跳转到登录
定义装饰器–闭包
二. Django自带方法实现登录/注册/登录状态权限
前言
在django中,django帮我们封装好了登录注册以及注销的函数,使用django定义好的注册登录注销函数去实现用户的登录验证,用户登录,以及用户注销等操作,以及定义login_rqueired装饰器,去装饰我们定义的函数,实现登录才能处理对应的业务逻辑
1. 实现注册方法
1.1 页面提交注册字段
在页面的form中有一下三个字段,用户名和密码1和密码2,页面在submit提交的时候,会提交该三个字段后后端,在后端中获取该参数即可
1.2 后端处理注册的信息
后端获取前端传递的参数,进行简单的验证后,进行创建用户的信息
2. 实现登录方法
2.1 登录页面提交登录的字段
2.2 后端进行登录的验证
3. 实现注销方法
4. 登录验证
from django.contrib.auth.decorators import login_required
使用login_required装饰器去装饰自定义的视图函数
5. 手动实现登陆注册具体代码
from datetime import datetime, timedelta
from django.contrib.auth.hashers import make_password, check_password
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.core.urlresolvers import reverse
from sx_user.models import UserModel, UserTicketModel
from utils.functions import get_ticket
# 注册
def register(request):
if request.method == 'GET':
return render(request, 'register.html')
if request.method == 'POST':
username = request.POST.get('user_name')
password = request.POST.get('pwd')
password_c = request.POST.get('cpwd')
email = request.POST.get('email')
# 验证参数都不能为空
if not all([username, password, password_c, email]):
data = {
'msg': '请填写完整的信息'
}
return render(request, 'register.html', data)
# 加密password
password = make_password(password)
password_c = make_password(password_c)
# 创建用户并添加到数据库
UserModel.objects.create(username=username,
password=password,
password_c=password_c,
email=email)
# 注册成功跳转到登陆页面
return HttpResponseRedirect(reverse('user:login'))
# 登陆
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('pwd')
data = {}
# 验证信息是否填写完整
if not all([username, password]):
data['msg'] = '请填写完整的用户名或密码'
# 验证用户是否注册
if UserModel.objects.filter(username=username).exists():
user = UserModel.objects.get(username=username)
# 验证密码是否正确
if check_password(password, user.password):
# 如果密码正确将ticket值保存在cookie中
ticket = get_ticket()
response = HttpResponseRedirect(reverse('store:index'))
out_time = datetime.now() + timedelta(days=2)
response.set_cookie('ticket', ticket, expires=out_time)
# 保存ticket值到数据库user_ticket表中
UserTicketModel.objects.create(user=user,
out_time=out_time,
ticket=ticket)
return response
else:
msg = '用户名或密码错误'
return render(request, 'login.html', {'msg': msg})
else:
msg = '用户名不存在,请注册后在登陆'
return render(request, 'login.html', {'msg': msg})
# 退出
def logout(request):
if request.method == 'GET':
# 退出则删除数据库中的ticket值
ticket = request.COOKIES.get('ticket')
user_ticket = UserTicketModel.objects.filter(ticket=ticket).first()
UserTicketModel.objects.filter(user=user_ticket.user).delete()
return HttpResponseRedirect(reverse('user:login'))
# 中间件
from datetime import datetime
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.utils.deprecation import MiddlewareMixin
from django.core.urlresolvers import reverse
from user.models import UserTicketModel, UserModel
class UserMiddle(MiddlewareMixin):
def process_request(self, request):
# 需要登录验证,个人中心和购物车和商品的增删
need_login = ['/tb/index/',
'/tb/list/',]
if request.path in need_login:
# 先获取cookies中的ticket参数
ticket = request.COOKIES.get('ticket')
# 如果没有ticket,则直接跳转到登录
if not ticket:
return HttpResponseRedirect(reverse('user:login'))
user_ticket = UserTicketModel.objects.filter(ticket=ticket).first()
if user_ticket:
# 获取到有认证的相关信息
# 1. 验证当前认证信息是否过期,如果没过期,request.user赋值
# 2. 如果过期了,跳转到登录,并删除认证信息
if datetime.utcnow() > user_ticket.out_time.replace(tzinfo=None):
# 过期
UserTicketModel.objects.filter(user=user_ticket.user).delete()
return HttpResponseRedirect(reverse('user:login'))
else:
# 没有过期,赋值request.user,并且删除多余的认证信息
request.user = user_ticket.user
# 删除多余的认证信息,
# 从UserTicket中查询当前user,并且ticket不等于cookie中的ticket
UserTicketModel.objects.filter(Q(user=user_ticket.user) &
~Q(ticket=ticket)).delete()
return None
else:
return HttpResponseRedirect(reverse('user:login'))
else:
return None