ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-06-23 21:01:05  阅读:190  来源: 互联网

标签:自定义 jwt page --- token import payload


  • 三种分页方式
  • jwt介绍和原理
  • base64的编码和解码
  • django中快速使用jwt
  • 修改返回格式
  • 自定义用户表签发token
  • 自定义认证类验证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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有