登陆模块

认证

任何的项目都需要认证,用户输入了用户名和密码,验证通过,代表用户登录成功~~~

那HTTP请求是无状态的,下次这个用户再请求,我们是不可能识别这个用户是否登录的~~

所以我们就要有自己的方式来实现这个认证,也就是说~用户登录成功以后~~~我们给他们

生成一个随机字符串~~以后这个用户再请求~~都要携带这个随机字符串~~

我们就可以根据这个字符串进行判断这个用户是否登录~~~~

那么大家想一个问题~~就是我们给登录的用户生成的随机字符串放在哪里呢~~~

我们放哪里都可以~~目的是前端发送请求的时候带过来就可以了~~~

以前的cookie,session是我们的一种解决方案~~我们讲认证的时候也用过token的这种解决方案~~

1. 先创建redis连接池

import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379, decode_responses=True, max_connections=5)
redis_pool.py

2. 认证

from app01.models import Account
import redis
from utils.redis_pool import pool



# 基于redis的token认证
conn = redis.Redis(connection_pool=pool)


class LoginAuth(BaseAuthentication):

    def authenticate(self, request):
        # 认证通过 返回(user对象, token)
        # 不通过抛异常
        # 1. 拿到前端传过来的token
        # 2. 判断token是否存在
        # 3. 以及token是否过期
        if request.method == 'OPTIONS':
            return None
        token = request.META.get('HTTP_AUTHENTICATION', '')
        if not token:
            raise AuthenticationFailed('没有携带token')
        print(conn.exists(token), 1111111111111111)
        print(token)
        if not conn.exists(token):
            raise AuthenticationFailed('token过期')
        user_id = conn.get(token)
        user_obj = Account.objects.filter(id=user_id).first()
        return (user_obj, token)
authentication.py

 

TOKEN

用户登录成功后,生成一个随机字符串token给前端返回~~~

那么前端以后都携带这个token来访问~~这样我们只需要鉴别这个token~来做认证~~

前端如果发送请求~把token放在请求头中~~我们看下我们的认证要怎么写~~

在写认证之前,我们先把登录注册功能写了~~~

1. 扩展用户表

class Account(models.Model):
    username = models.CharField(max_length=32, verbose_name="用户姓名", unique=True)
    password = models.CharField(max_length=32, verbose_name="用户密码")
    # head_img = models.CharField(max_length=256, default='/static/frontend/head_portrait/logo@2x.png',
    #                             verbose_name="个人头像")
    token = models.UUIDField(null=True, blank=True)

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = "11-用户表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
models.py

2. 编写登录注册视图

# 创建两个视图 一个注册的 一个登录的
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.base_response import BaseResponse
from .serializers import UserSerializer
from course.models import Account
import uuid
# Create your views here.


class UserView(APIView):

    # 注册用户
    def post(self, request):
        res = BaseResponse()
        ser_obj = UserSerializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            res.data = ser_obj.validated_data
        else:
            res.code = 1010
            res.data = ser_obj.errors
        return Response(res.dict)


class LoginView(APIView):

    # 登录视图
    def post(self, request):
        res = BaseResponse()
        # 这里要获取我们的用户名密码 进行验证是否有这个用户
        # 而且我们这个密码前端一定是密文传过来 我们通过密文对比进行验证
        username = request.data.get("username", "")
        password = request.data.get("password", "")
        user_obj_queryset = Account.objects.filter(username=username, password=password)
        if not user_obj_queryset:
            res.code = 1003
            res.error = "用户名或密码错误"
        try:
            token = uuid.uuid4()
            user_obj_queryset.update(token=token)
            res.data = token
        except Exception as e:
            res.code = 1004
            res.error = "生成token失败"
        return Response(res.dict)
views.py

登录注册写完后, 开始写认证

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from course.models import Account
# django 提供的拿时间的接口 提供的是根据django配置的时区拿到的当前时间
from django.utils.timezone import now


class MyAuth(BaseAuthentication):
    def authenticate(self, request):
        if request.method == "OPTIONS":
            return None
        # print(request.META)
        token = request.META.get("HTTP_AUTHENTICATION", "")
        print(token)
        if not token:
            raise AuthenticationFailed({"code": 1021, "error": "缺少token"})
        user_obj = Account.objects.filter(token=token).first()
        if not user_obj:
            raise AuthenticationFailed({"code": 1020, "error": "无效的token"})
        else:
            old_time = user_obj.create_token_time
            if (now() - old_time).days > 7:
                raise AuthenticationFailed({"code": 1020, "error": "无效的token"})
            return user_obj, token
auth.py
# 查看购物车是需要登录后才可以
# 所有这是一个需要认证的接口
class ShoppingCarView(APIView):
    authentication_classes = [MyAuth, ]
    # 展示购物车数据
    def get(self, request, *args, **kwargs):
        print(request.user)
        return Response("test")
views.py 测试用的视图

基于请求头的token认证就完成了~~~

posted @ 2019-05-10 22:08  温而新  阅读(310)  评论(0编辑  收藏  举报