用户登陆和认证组件
用户登陆,把token放到数据库中
import uuid import redis import datetime from rest_framework.views import APIView from rest_framework.response import Response from app02 import models from django.contrib import auth from app02.utils.myexception import MyErrorException # 点击登陆,滑动验证提交数据,返回True或者False from app02.utils.captcha_verify import verify redis_conn = redis.Redis(decode_responses=True) class Login(APIView): def post(self,request): # 获取前端发过来的数据,验证需要的三个数据是否成功,成功返回True status = verify(request.data) if not status: raise MyErrorException(1010,'滑动验证失败') # 200:成功 400:失败 login_dic = {'code': None, 'username': None, 'msg': None, 'token': None} uname = request.data.get('username') upwd = request.data.get('password') # 直接验证UserInfo表,且密码是加密去进行验证的,得到的还是用户信息的对象 userinfo_obj = auth.authenticate(username=uname,password=upwd) if userinfo_obj: # 如果登陆过的用户,再次登陆的话,数据库中token值会变化, # 则redis里面的token必须删除掉,因为已经没用了,用户再用这个token访问 # 就会告诉用户认证失败. try : if redis_conn.get(userinfo_obj.auth_token.key) : redis_conn.delete(userinfo_obj.auth_token.key) except Exception as e: pass # 设置一个随机的字符串,用来赋值给token random_str = uuid.uuid4() #(1)添加数据到token表 models.Token.objects.update_or_create( # 验证账号密码成功,就把token和时间(添加或更新)到表中 defaults={'key':random_str,'created':datetime.datetime.now()}, user = userinfo_obj ) login_dic['code'] = 200 login_dic['username'] = uname login_dic['msg'] = '登陆成功' login_dic['token'] = random_str return Response(login_dic) else : login_dic['code'] = 400 login_dic['msg'] = '登陆失败' return Response(login_dic)
认证组件,数据库中token过期时间14天,redis中存放的 token,用户id(k,v) 过期时间为7天
import datetime import pytz import redis from app02 import models from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed # 设置一个redis缓存数据库的内存 redis_conn = redis.Redis(decode_responses=True) # 认证组件 class My_Authentication(BaseAuthentication): def authenticate_header(self, request): pass def authenticate(self, request): # 请求的token放到了请求头里面 # 名字 Authentication:token ,请求头里面的内容都会被自动处理成HTTP_大写的键 # token = request.META.get('HTTP_AUTHENTICATION') # 请求路径?后面的值,GET.get拿取路径(?token=...)的token值 token = request.query_params.get('token') # 来redis数据库来取token为键的值,如果存在,说明缓存中的token数据有效,认证成功 # 如果没有值得话,代码继续向下执行 redis_user_id = redis_conn.get(token) if redis_user_id : print('redis缓存认证成功') # 返回这个request.user为token对应的用户信息的id, request.auth为token值 return redis_user_id,token # 从数据库中进行验证,看是否可以认证成功 token_obj = models.Token.objects.filter(key=token).first() if token_obj : # 把当前的时间进行转换,因为数据库存的时间是经过地区转换的时间,转换才能加减 now = datetime.datetime.now() now = now.replace(tzinfo=pytz.timezone('UTC')) # 创建或更新token时的时间 created_time = token_obj.created # 这次使用token,距离创建token表的时间有多久 right_time = now - created_time # 如果距离token表的时间超过了14天,则说明token表虽然存在,但是过期了. if right_time > datetime.timedelta(days=14): raise AuthenticationFailed('认证过期了') else : # 这次使用距离token值过期还有多少时间 # 这个时间是为了不让redic过期时间超过数据库的过期时间 lift_time = datetime.timedelta(days=14) + created_time - now # 把token作为键,token对应的用户信息id作为值,添加到redis # token缓存在redis里面是7天,在数据库中是14天 redis_conn.set(token,token_obj.user.pk,min(lift_time.total_seconds(),7*24*3600)) print('数据库token认证') # 返回这个request.user为token对应的用户信息的id,request.auth为token值 return token_obj.user.pk,token #(如果数据库token表中验证路径中token的值不存在} else: raise AuthenticationFailed('认证失败')