jwt,认证,分页

jwt

# jwt: json web tokens
# jwt规范:就是对token的规范,头.体.签名
'''
    1.token一定是后台产生,拥有请求认证,所以要前后台统一
    2.token的组成部分通常有三分部组成:header.payload.signature
    3.header:{"token的加密方式": "base64", "是否有签名": True} 加密处理后的结果
    4.payload:{"账号": *, "密码": *, "发行者": *, "过期时间": *, "浏览器信息": *} 加密处理后的结果
    5.signature:{"header": *, "payload": *, "salt": *} 加密处理后的结果
    
    eg: eyJ0eXAiOiJK.eyJ1c2VyX2lkIjoxLCJ1cNTgzMDM1NDR9.4j5QypLwuf
'''

 

jwt-token操作

# 安装 djangorestframework-jwt
#         -- pip3 install djangorestframework-jwt

# 采用 djangorestframework-jwt框架 产生 jwt规范的 token
from rest_framework_jwt.settings import api_settings
def get_jwt_token(user):
    # 自定义生成token,基于某user对象,且该user对象必须有username、password两个字段
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    payload = jwt_payload_handler(user)
    token = jwt_encode_handler(payload)
    return token

 

 

项目开发的token处理

# token可以存储的位置:服务器、缓存、客户端

# 1.产生token: 对request操作形成 header.payload.signature
def token_encode(request):
    token = ""
    print(request)

    # 加密规则
    # 将request变成 "header.payload.signature"
    header_dic = {
        "lock_code": "base64"
    }
    header = base64.b64encode(json.dumps(header_dic).encode('utf-8'))
    payload = b"abc123"
    signature = b"000"
    token_data = b"%s.%s.%s" % (header, payload, signature)
    token = token_data.decode('utf-8')
    return token
# 在登录时,用token_encode产生token,丢给前台即可,服务器不用存储


# 2.解析token:从request中的token 解析出 header、payload、signature
def token_decode(request):
    token = request.META.get('HTTP_TOKEN')  # type: str

    header, payload, signature = token.split('.')
    # 解密规则
    # header校验,失败
    #    return None
    header_str = base64.b64decode(header.encode('utf-8'))
    header_dic = json.loads(header_str)
    if header_dic != {"lock_code": "base64"}:
        return None

    # payload校验,失败
    #    return None
    # signature校验,失败
    #    return None

    # 校验成功
    # return user, auth
# 在认证模块校验时,用token_decode校验token,不是查询UserToken数据库校验
项目开发的token处理

 

 

权限认证

# app.models
class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    # 用户有不同的权限分类
    level = models.IntegerField(choices=((0, '普通用户'), (1, '超级用户')), default=0)
    
    
# app.auth
from rest_framework.permissions import BasePermission
class VisitPermission(BasePermission):
    message = '验证失败:权限不够!'
    def has_permission(self, request, view):
        # 1)拿到登录的用户
        user = request.user
        # 2)获取用户的权限
        # lever = user.level
        lever_str = user.get_level_display()
        # 3)权限判断
        if lever_str == '超级用户':
            return True  # 验证通过
        return False  # 验证失败

# app.views
from app import auth
class Books(APIView):
    permission_classes = [auth.VisitPermission]  # 局部使用
    def get(self, request):
        return Response({
            "status": 0,
            "msg": 'get books success',
            "results": [],
            "user_name": request.user.username
        })

# 了解:全局使用局部禁用
# settings
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'app.auth.VisitPermission',
    )
}
# views
class Books(APIView):
    permission_classes = []  # 局部禁用
权限认证

 

 

频率认证

# 项目开发
# app.auth
from rest_framework.throttling import SimpleRateThrottle
class VisitRateThrottle(SimpleRateThrottle):
    scope = "luffy"

    def get_cache_key(self, request, view):
        return self.get_ident(request)
        # return request.META.get('REMOTE_ADDR')  # 对IP进行频率限制
        # return request.user.username  # 对用户进行频率限制

# settings
REST_FRAMEWORK = {
    # 频率的配置 3/s 3/m 3/h 3/h
    'DEFAULT_THROTTLE_RATES': {
        'luffy': '3/m'  # 一分钟可以访问三次
    }
    # 全局配置
    'DEFAULT_THROTTLE_CLASSES': (
        'app.auth.VisitRateThrottle',
    )
}

# views
class Books(APIView):
    # 局部禁用
    throttle_classes = []
频率认证

 

 

频率组件原理

class MyThrottle(BaseThrottle):
    # 存放ip与访问时间list的对应关系
    VISIT_RECORD = {}

    def __init__(self):
        # 存放某一访问者历史访问时间的
        self.history = None

    def allow_request(self, request, view):
        # 1) 取出访问者ip
        ip = request.META.get('REMOTE_ADDR')
        # 2) 获取当前时间
        import time
        ctime = time.time()
        # 3) 判断是否是第一次访问
        if ip not in self.VISIT_RECORD:
            self.VISIT_RECORD[ip] = [ctime, ]
            return True
        self.history = self.VISIT_RECORD.get(ip)
        # 4) 当前时间与最开始访问时间间隔超出60s则可以再次访问,移除最开始的访问时间
        while self.history and ctime - self.history[-1] > 60:
            self.history.pop()
        # 5) 访问频率的处理
        if len(self.history) < 3:
            self.history.insert(0, ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime = time.time()
        # 还要等多久才能访问
        return 60 - (ctime - self.history[-1])
频率组件原理

 

 

分页

数据准备

# models
class Teacher(models.Model):
    name = models.CharField(max_length=32)
    salary = models.DecimalField(max_digits=5, decimal_places=2)
# objson
class TeacherJson(serializers.ModelSerializer):
    class Meta:
        model = models.Teacher
        fields = '__all__'
# urls
url(r'^teachers/', views.Teachers.as_view()),

# views
class Teachers(APIView):
    def post(self, request):
        list = []
        for i in range(1, 51):
            list.append(models.Teacher(name="%s老师" % i, salary=i))
        models.Teacher.objects.bulk_create(list)
        return Response({
            'status': 0,
            'msg': 'ok'
        })
    
数据准备

 

简单分页

from rest_framework.pagination import PageNumberPagination
class Teachers(APIView):
    permission_classes = []
    throttle_classes = []
    throttle_classes = []
    def get(self, request):
        # 没有分页的所有数据
        teacher_list = models.Teacher.objects.all()

        # 完成分页
        # 1) 初始化分页对象
        page_simple = PageNumberPagination()

        # 2) 配置分页对象
        # page_simple.page_size = api_settings.PAGE_SIZE
        # 一页显示的条数
        page_simple.page_size = 5
        # /teachers/?pages=3  默认page
        page_simple.page_query_param = 'pages'
        # /teachers/?pages=3&line=10 用户可以自定义访问一页有多少条数据
        page_simple.page_size_query_param = 'line'
        # 限制用户自定义一页最大能访问的条数
        page_simple.max_page_size = 10

        # 3) 操作分页后一页的数据
        teacher_page_list = page_simple.paginate_queryset(teacher_list, request, self)
        
        # 将一页的数据序列化后返回给前台
        teacher_data = objson.TeacherJson(teacher_page_list, many=True).data
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': teacher_data
        })
        
简单分页

 

偏移分页

from rest_framework.pagination import LimitOffsetPagination
class Teachers(APIView):
    def get(self, request):
        teacher_list = models.Teacher.objects.all()

        # 完成分页
        # 1) 初始化分页对象
        page_limit = LimitOffsetPagination()

        # 2) 配置分页对象
        # 一页显示的条数
        page_limit.default_limit = 5
        # 自定义一页获取的条数
        page_limit.limit_query_param = 'limit'
        # 从哪条数据开始查询
        page_limit.offset_query_param = 'offset'
        # 自定义最大获取一页的条数
        page_limit.max_limit = 8

        # 3) 操作分页数据
        teacher_page_list = page_limit.paginate_queryset(teacher_list, request, self)

        teacher_data = objson.TeacherJson(teacher_page_list, many=True).data
        return Response({
            'status': 0,
            'msg': 'ok',
            'previous': page_limit.get_previous_link(),  # 上一页
            'next': page_limit.get_next_link(),  # 下一页
            'results': teacher_data
        })

        # return page_limit.get_paginated_response(teacher_data)  # 内部提供的Response对象
偏移分页

 

游标分页

from rest_framework.pagination import CursorPagination
class Teachers(APIView):
    def get(self, request):
        teacher_list = models.Teacher.objects.all()

        # 完成分页
        # 1) 初始化分页对象
        page_cursor = CursorPagination()

        # 2) 配置分页对象
        # 一页的条数
        page_cursor.page_size = 10
        # 排序的字段,可以正向也可以反向
        page_cursor.ordering = '-id'
        # 游标的关键字
        page_cursor.cursor_query_param = 'cursor'

        # 3) 操作分页数据
        teacher_page_list = page_cursor.paginate_queryset(teacher_list, request, self)

        teacher_data = objson.TeacherJson(teacher_page_list, many=True).data
        return Response({
            'status': 0,
            'msg': 'ok',
            'previous': page_cursor.get_previous_link(),  # 上一页
            'next': page_cursor.get_next_link(),  # 下一页
            'results': teacher_data
        })
游标分页

 

posted @ 2019-08-05 09:57  -Rye-  阅读(106)  评论(0)    收藏  举报