用户登陆和认证组件

用户登陆,把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('认证失败')

  

 

posted on 2019-06-29 16:59  哎呀!土豆  阅读(112)  评论(0编辑  收藏  举报

导航