zoukankan      html  css  js  c++  java
  • JWT自定义校验规则与生成、用户多种方式登陆、搜索过滤组件,排序组件,分页组件


    # 自定义校验token规则
    1.视图类
    from .authentications import JWTAuthentication
    
    class UserDetail1(APIView):
        permission_classes = [IsAuthenticated]  # 必须登录
        authentication_classes = [JWTAuthentication]  # jwt用户token自定义登陆认证规则
    
        def get(self, request, *args, **kwargs):
            return APIResponse(results={'username': request.user.username})
    2.自定义token规则,在api生成一个authentications.py认证文件
    import jwt
    from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
    from rest_framework_jwt.authentication import jwt_decode_handler
    from rest_framework.exceptions import AuthenticationFailed
    
    class JWTAuthentication(BaseJSONWebTokenAuthentication):
        def authenticate(self, request):
            jwt_token = request.META.get('HTTP_AUTHORIZATION')
    
            # 自定义规则 :auth token jwt,调用下面规则方法
            token = self.parse_jwt_token(jwt_token)
    
            # 如果没有值,无法校验
            if token is None:
                return None
    
            try:
                # token =>payload  反向解析出payload
                payload = jwt_decode_handler(token)
            except jwt.ExpiredSignature:  # 判断是否过期
                raise AuthenticationFailed('token已过期')
            except:
                raise AuthenticationFailed('非法用户')
            user = self.authenticate_credentials(payload) # 根据payload解析出user
    
            return (user, token)
    
        # 自定义校验规则:auth token jwt ,auth为前言,jwt为后缀
        def parse_jwt_token(self, jw_token):
            tokens = jw_token.split()
            if len(tokens) != 3 or tokens[0].lower() != 'auth' or tokens[2].lower() != 'jwt':
                return None
            # 把token核心内容返回进行校验
            return tokens[1]

    # 自定义 drf-jwt 配置
    import datetime
    JWT_AUTH = {
        # user => payload
        'JWT_PAYLOAD_HANDLER':
            'rest_framework_jwt.utils.jwt_payload_handler',
        # payload => token
        'JWT_ENCODE_HANDLER':
            'rest_framework_jwt.utils.jwt_encode_handler',
        # token => payload
        'JWT_DECODE_HANDLER':
            'rest_framework_jwt.utils.jwt_decode_handler',
        # token过期时间
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
        # token刷新的过期时间
        'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
        # 反爬小措施前缀
        'JWT_AUTH_HEADER_PREFIX': 'JWT',
    }

    实现多种方式登录签发token:比如 -账号、手机号、邮箱等登录:
    1.禁用认证与权限组件
    2.拿到前台登录信息,交给序列化类
    3.序列化校验得到登陆用户与token存放在序列化对象中
    4.取出登陆用户与token返回给前台
    """

    from .serializers import UserModelSerializer

    # 1.视图类
    class LoginAPIView(APIView):
        authentication_classes = []  # 禁用认证
        permission_classes = []  # 禁用权限
    
        def post(self, request, *args, **kwargs):
            user_ser = UserModelSerializer(data=request.data)  # 反序列化进行校验
            # 校验通过,如果没有报异常
            user_ser.is_valid(raise_exception=True)
    
            # 正常登陆,把生成的token返回给前端
            return APIResponse(token=user_ser.token, results=UserModelSerializer(user_ser.user).data)
      
    #2. 序列化类,进行校验,生成token发送出去
    from rest_framework import serializers
    from . import models
    import re
    
    from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
    
    class UserModelSerializer(serializers.ModelSerializer):
        # 自定义反序列化字段:一定要设置write_only,值参与反序列化,不会与model类字段映射
        usr = serializers.CharField(write_only=True)
        pwd = serializers.CharField(write_only=True)
    
        class Meta:
            model = models.User
            fields = ['usr', 'pwd', 'username', 'mobile', 'email']
            # 系统校验规则
            extra_kwargs = {
                # 'usr': {
                    # 'required': True,  # 必须校验
                #     'min_length': 3,
                #     'error_messages': {
                #         'required': '必须填写,你个铺盖',
                #         'min_length': '太短楼!',
                #     }
                # },
                'username': {
                    'read_only': True
                },
                'mobile': {
                    'read_only': True
                },
                'email': {
                    'read_only': True
                }
    
            }
    
        # 全局钩子,attrs里面是通过校验的
        def validate(self, attrs):
            usr = attrs.get('usr')
            pwd = attrs.get('pwd')
            # 多方式登录:各分支处理得到该方式对应的用户
            if re.match(r'.+@.+', usr):
                user_query = models.User.objects.filter(email=usr)
            elif re.match(r'1[3-9][0-9]{9}', usr):
                user_query = models.User.objects.filter(mobile=usr)
            else:
                user_query = models.User.objects.filter(username=usr)
            user_obj = user_query.first()
    
            if user_obj and user_obj.check_password(pwd):
                # 签发生成token,将token存放到实例化对象的中
                payload = jwt_payload_handler(user_obj)  # 把头部,和载荷过期时间,user对象,生成payload
                token = jwt_encode_handler(payload)  # 把头部,载荷,和秘=秘钥经过加密生成token
                self.token = token  # 把token赋值到对象中
                self.user = user_obj
                print(token)
                return attrs
            raise serializers.ValidationError({'data': '数据提供有误'})
     
    搜索过滤,排序,分页:
    from . import models
    from .serializers import CarModelSerializer
    # Car的群查接口
    from rest_framework.generics import ListAPIView
    
    # 1.drf的SearchFilter - 搜索过滤
    from rest_framework.filters import SearchFilter
    
    # 2.drf的OrderingFilter - 排序过滤
    from rest_framework.filters import OrderingFilter
    
    # 3.drf的分页类 - 自定义
    from . import pagenations
    
    class CarListAPIView(ListAPIView):
        permission_classes = []  # 权限取消
        authentication_classes = []  # 认证取消
    
        queryset = models.Car.objects.all()
        serializer_class = CarModelSerializer
    
        # 局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)
        filter_backends = [SearchFilter,OrderingFilter]
    
        # SearchFilter过滤类依赖的过滤条件 => 接口:/cars/?search=...
        search_fields = ['name', 'price']
    
        # OrderingFilter过滤类依赖的过滤条件 => 接口:/cars/?ordering=...,正是升序,-则是降序
        ordering_fields = ['pk', 'price']
        # eg:/cars/?ordering=-price,pk,先按price降序,如果出现price相同,再按pk升序
    
        pagination_class = pagenations.MyPageNumberPagination
     
    # 自定义分页类
    from rest_framework.pagination import PageNumberPagination
    
    class MyPageNumberPagination(PageNumberPagination):
        # ?page=页码
        page_query_param = 'page'
    
        # ?page=页面 下默认一页显示的条数
        page_size = 3
    
        # ?page=页面&page_size=条数 用户自定义一页显示的条数
        page_size_query_param = 'page_size'
    
        max_page_size = 5
  • 相关阅读:
    叩开抽象的大门(2)——依赖于抽象
    威老迷宫探险第二季如何更面向对象
    更佳的封装之路面向对象的封装思想
    威老的迷宫探险
    重用,我要重用!!!
    威老出国记,什么是引用,别名。
    叩开抽象的大门(1)——抽象类、接口
    maven常用命令
    大公司喜欢问的问题
    java 发送http请求
  • 原文地址:https://www.cnblogs.com/wukai66/p/11729218.html
Copyright © 2011-2022 走看看