其他分享
首页 > 其他分享> > drf篇:分页器、jwt快速生成使用、自定义用户表签发token

drf篇:分页器、jwt快速生成使用、自定义用户表签发token

作者:互联网

1 三种分页方式

# 什么样接口要分页----》获取所有
# 三种分页方式---》继承GenericAPIView,ListModelMixin
	-list方法---》

1.1 分页的使用

page.py

from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination

# 基本分页:正常的查第几页,每页显示多少条的方式---》常用
class CommonPageNumberPagination(PageNumberPagination):
    #4 个类属性
    page_size = 2     #每页显示条数
    page_query_param = 'page'   # 查询页码参数  ?page=10
    page_size_query_param = 'size' #  ?page=3&size=5000
    max_page_size = 5              #可以通过size控制每页显示的条数,但是通过这个参数控制最多显示多少条

# http://127.0.0.1:8000/books/?page=1&size=300000



# 偏移分页
class CommonLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2    # 每页显示多少条
    limit_query_param = 'limit'   # 取多少条
    offset_query_param = 'offset' #从第0个位置偏移多少开始取数据
    max_limit = 5     # 最大限制条数
    # offset=6&limit=90000
    # http://127.0.0.1:8000/books/?limit=3&offset=3  # 从第三条开始取3条

    # limit_query_description = _('Number of results to return per page.')



# 游标分页---》针对于大数据量分页效率高---》可控性差--->只能选择上一页和下一页,不能直接跳转到某一个
class CommonCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 查询的名字  等同于  page=xx
    page_size = 3  # 每页显示多少条
    max_page_size = 5  # 最大显示多少条
    ordering = 'id'  # 排序规则,必须是表中有的字段,一般用id
    page_size_query_param = 'size'  # size控制显示条数
#http://127.0.0.1:8000/books/?cursor=cD0z

views.py

from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from .models import Book
from .serializer import BookSerializer

# 三种分页方式:
from .page import CommonPageNumberPagination as PageNumberPagination
from .page import CommonLimitOffsetPagination
from .page import CommonCursorPagination
class BookView(GenericAPIView,ListModelMixin):
class BookView(GenericViewSet, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class= CommonCursorPagination

1.2 继承APIView实现分页

# APIView实现分页
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
class BookView(ViewSet):
    def list(self,request):
        books=Book.objects.all()
        # 分页
        # paginator=PageNumberPagination()
        paginator=CommonLimitOffsetPagination()
        #分页过后的数据
        qs=paginator.paginate_queryset(books,request,self)
        #序列化
        ser=BookSerializer(qs,many=True)
        # 第一种方式:每页总条数,上一页,下一页
        # return Response(ser.data)
        # 第二种:自己凑
        # return Response({
        #     'count':books.count(),
        #     'next': paginator.get_next_link(),
        #     'previous':paginator.get_previous_link(),
        #     'results': ser.data
        # })
        # 第三种;直接使用分页类的方法
        return paginator.get_paginated_response(ser.data)

2 jwt介绍和原理

# jwt:Json web token
# cookie,session,token
	-cookie是存放在客户端浏览器的键值对
    -session是存放在服务端的键值对
    	客户端:sessionId:asdfasdf----》放到cookie中
        服务端: 
            asdfasdf:{id:3,name:lqz}
            dddddd:{id:4,name:pyy}
    -token: 字符串:分三段
    	-第一段:头--》公司信息,加密方式。。。
        -第二段:荷载--》放用户信息---->{id:3,name:lqz}
        -第三段:签名---》把第一段和第二段通过某种加密方式+秘钥加密得到一个字符串 asdfads
        -把三段使用base64编码后拼到一起  dasfasd.asdfasdasd.asdfads
        -【token 的签发】---》登录成功后,服务端生成
        -把token串给前端---》前端拿着
        -后面前端只要发请求,就携带token串到后端
        -【token的验证】--》拿到第一段和第二段使用同样的加密方式+秘钥再加密---》得到字符串跟第三段比较,如果一样,表示没有被篡改,如果不一样,表明被篡改了,token不能用了
        -如果没有被篡改,取出第二段  当前登录用户的信息  id
        
#jwt:Json web token---》只针对于web方向的token方式验证

# token典型样子
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

# jwt组成
	-1 header---》{'typ': 'JWT','alg': 'HS256'}---》通过bas64编码后----》eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    -2 payload---》荷载---》真正用户的数据
        {
      	"sub": "1234567890", # 过期时间
         "id":3
      	"name": "John Doe",
      	"admin": true
    	}
    -3 signature---》签名
        header (base64后的)
        payload (base64后的)
        secret
    
    
    
    
# base64的编码和解码
	-base64的长度一定是4的倍数,如果不到用=补齐
    
    import json
    import base64
    # d={'typ': 'JWT','alg': 'HS256'}
    # s=json.dumps(d)
    # print(s)

    #把字符串进行b64编码
    # res=base64.b64encode(bytes(s,encoding='utf-8'))
    # print(res)


    #把b64编码的字符串,解码
    # b=b'eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9'
    # res=base64.b64decode(b)
    # print(res)
    
    
# 开发中使用jwt认证的重点
	-签发token---》登录
    -认证token---》认证类

3 django中快速使用jwt

# https://github.com/jpadilla/django-rest-framework-jwt
# https://github.com/jazzband/djangorestframework-simplejwt
# 用法95%相似

#安装
pip3 install djangorestframework-jwt

# 快速使用---》使用的表是django的auth的user表---》创建一个用户

# 只需要在路由中配置---》auth的user表中有用户
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    path('login/', obtain_jwt_token),
]

总结:
1、安装djangorestframework-jwt
2、配置路由:
    from rest_framework_jwt.views import obtain_jwt_token
    path('login/', obtain_jwt_token)
3、models执行迁移

4 修改返回格式

快速jwt默认返回的之后token,所以可以修改格式

# 登录成功返回格式:{code:100,msg:"登录成功",token:asdfasdf,username:lqz}

# 写一个函数,在配置文件配置
def jwt_response_payload_handler(token, user=None, request=None):
    return {'code': 100, 'msg': '登陆成功', 'token': token, 'username': user.username}

# 配置文件配置
JWT_AUTH = {
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.jwt_response_payload_handler',
}

5 jwt的验证

# 只需要在视图类中加入一个认证类,一个权限类
class BookView(ViewSet):
    authentication_classes = [JSONWebTokenAuthentication,]
    permission_classes = [IsAuthenticated,]
    
    
# 需要在请求头中携带token
	-请求头中key:Authorization
    -请求头的value值:jwt token串

5 自定义用户表签发token

# 自己定义用户表,实现签发token功能---》登录接口
from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from rest_framework.decorators import action
class UserView(ViewSet):
    @action(methods=['POST'],detail=False)
    def login(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = UserInfo.objects.filter(username=username, password=password).first()
        if user:
            # 登录成功---》签发token
            payload = jwt_payload_handler(user)  # 根据当前登录用户获取荷载
            print(payload)
            token = jwt_encode_handler(payload)  # 根据荷载生成token

            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或密码错误'})
        
        
        
总结:
payload = jwt_payload_handler(user)  # 根据当前登录用户获取荷载
token = jwt_encode_handler(payload)  # 根据荷载生成token
怎么来的?
rest_framework_jwt
views.py
————>JSONWebTokenAPIView
	--->def post--->token = serializer.object.get('token')  # serializer中获取token
————>ObtainJSONWebToken--->serializer_class = JSONWebTokenSerializer
————>JSONWebTokenSerializer
	--->def validate 
     --->payload = jwt_payload_handler(user)
        'token': jwt_encode_handler(payload)

6 自定义认证类验证token


from rest_framework_jwt.settings import api_settings
from rest_framework import exceptions
from .models import UserInfo
import jwt

# Authentication.py(源码中cv)
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER

# Authentication.py(源码中复制)
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        # 1 取出 token
        jwt_value = request.META.get('HTTP_TOKEN')
        # 2 验证token是否合法
        # try:
        #     payload = jwt_decode_handler(jwt_value)
        # except jwt.ExpiredSignature:
        #     msg = 'token过期了'
        #     raise exceptions.AuthenticationFailed(msg)
        # except jwt.DecodeError:
        #     msg = 'token解码错误'
        #     raise exceptions.AuthenticationFailed(msg)
        # except jwt.InvalidTokenError:
        #     msg = '解析token未知错误'
        #     raise exceptions.AuthenticationFailed(msg)
        try:
            payload = jwt_decode_handler(jwt_value)
        except Exception:
            raise exceptions.AuthenticationFailed('token错误')

        print(payload)  # 荷载---》user_id
        user = UserInfo.objects.filter(pk=payload['user_id']).first()
        return user, jwt_value

补充

# 加密:对称加密  非对称加密
	-加密和解密都使用同一个秘钥
    -加密用公钥,解密用私钥

标签:自定义,jwt,page,---,token,import,payload
来源: https://www.cnblogs.com/williama/p/16406705.html