• qhfl-4 注册-登录-认证


    认证

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

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

    就要有自己的方式来实现这个认证,用户登录成功以后,生成一个随机字符串,以后这个用户再请求,都要携带这个随机字符串。

    就可以根据这个字符串进行判断这个用户是否登录,目的是前端发送请求的时候带过来就可以,以前的cookie,session是的一种解决方案,认证的时候也用过token的这种解决方案。

    token

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

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

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

    序列化注册数据

    测试的时候用的重写create方法,真正开发前端传过来的就是加密后的密文密码
    from rest_framework import serializers
    from Course.models import Account
    import hashlib
    
    
    class RegisterSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = Account
            fields = "__all__"
    
        def create(self, validated_data):
            pwd = validated_data["pwd"]
            pwd_salt = "luffy_password" + pwd   # 加盐处理
            md5_str = hashlib.md5(pwd_salt.encode()).hexdigest()
            user_obj = Account.objects.create(username=validated_data["username"], pwd=md5_str)
            return user_obj
    
    
    Login/serializers.py

    注册,登录的视图

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .serializers import RegisterSerializer
    from utils.base_response import BaseResponse
    from Course.models import Account
    from utils.redis_pool import POOL
    import redis
    import uuid
    from utils.my_auth import LoginAuth
    from utils.geetest import GeetestLib
    from django.http import HttpResponse
    import json
    
    # Create your views here.
    
    
    class RegisterView(APIView):
    
        def post(self, request):
            res = BaseResponse()   # 实例化响应类
            # 用序列化器做校验
            ser_obj = RegisterSerializer(data=request.data)
            if ser_obj.is_valid():
                ser_obj.save()
                res.data = ser_obj.data
            else:
                res.code = 1020
                res.error = ser_obj.errors
            return Response(res.dict)
    
    
    class LoginView(APIView):
    
        def post(self, request):
            res = BaseResponse()
            username = request.data.get("username", "")
            pwd = request.data.get("pwd", "")
            user_obj = Account.objects.filter(username=username, pwd=pwd).first()
            if not user_obj:
                res.code = 1030
                res.error = "用户名或密码错误"
                return Response(res.dict)
            # 用户登录成功生成一个token写入redis
            # 写入redis  token : user_id
            conn = redis.Redis(connection_pool=POOL) # 从连接池获取一个连接
            try:
                token = uuid.uuid4()
                conn.set(str(token), user_obj.id, ex=10000)
                # conn.set(str(token), user_obj.id)          # str(token) 用作key
                res.data = token
            except Exception as e:
                print(e)
                res.code = 1031
                res.error = "创建令牌失败"
            return Response(res.dict)
    
    Login/views.py
    class BaseResponse(object):
        """
        封装响应的类
        """
        def __init__(self):
            self.code = 1000
            self.data = None
            self.error = None
    
    
        @property
        def dict(self):
            return self.__dict__        # 返回字典
    utils/base_response.py

    认证器

    http头部发送的字段信息 key:value

    在服务器接受时,需要加上前缀(并且大写)例如 HTTP_KEY ,通过 request.META.get(HTTP_KEY) 获取值

    import redis
    
    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    
    from .redis_pool import POOL
    from Course.models import Account
    
    CONN = redis.Redis(connection_pool=POOL)
    
    
    class LoginAuth(BaseAuthentication):
        def authenticate(self, request):
            # 从请求头中获取前端带过来的token。或者跟前端商量好
            token = request.META.get("HTTP_AUTHENTICATION", "")
            # print(request.META)
            # print(token)
            if not token:
                raise AuthenticationFailed("没有携带token")
            # 去redis比对
            user_id = CONN.get(str(token))  # get没有的值返回 None
            if user_id == None:
                raise AuthenticationFailed("token过期")  # 重新登录设置token
            user_obj = Account.objects.filter(id=user_id).first()
            return user_obj, token
    
    utils/my_auth.py

    用到的redis连接池

    import redis
    
    
    POOL = redis.ConnectionPool(host="127.0.0.1", port=6379, decode_responses=True, max_connections=10)
    utils/redis_pool.py

    注册用户测试

    测试发送密码时为密文。前端传过来,后端加密后再与数据库中的比对

    以token为key存放在redis中,登录成功后返回生成的token数据(有有效期的),下次登录时携带上。后端以传过来的token 去reids中找,能找到就拿到用户信息,不能就说明过期需要重新登录,或者token不存在.

  • 相关阅读:
    camp训练day2
    LCA板子题
    牛客多校第一场
    P1063 能量项链 区间DP
    64. Minimum Path Sum
    46. Permutations
    216. Combination Sum III
    62. Unique Paths
    53. Maximum Subarray
    22. Generate Parentheses
  • 原文地址:https://www.cnblogs.com/wenyule/p/10468948.html
Copyright © 2020-2023  润新知