drf篇:分页器、jwt快速生成使用、自定义用户表签发token
作者:互联网
- 三种分页方式
- 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