drf-jwt手动签发与校验,drf小组件:过滤、筛选、排序、分页

              今日

              """
              1、drf-jwt手动签发与校验
              2、drf小组件:过滤、筛选、排序、分页 => 针对与群查接口
              """

              签发token

              源码入口
              # 前提:给一个局部禁用了所有 认证与权限 的视图类发送用户信息得到token,其实就是登录接口
              
              # 1)rest_framework_jwt.views.ObtainJSONWebToken 的 父类 JSONWebTokenAPIView 的 post 方法
              #       接受有username、password的post请求
              # 2)post方法将请求数据交给 rest_framework_jwt.serializer.JSONWebTokenSerializer 处理
              #       完成数据的校验,会走序列化类的 全局钩子校验规则,校验得到登录用户并签发token存储在序列化对象中
              核心源码:rest_framework_jwt.serializer.JSONWebTokenSerializer的validate(self, attrs)方法
              def validate(self, attrs):
                  # 账号密码字典
                  credentials = {
                      self.username_field: attrs.get(self.username_field),
                      'password': attrs.get('password')
                  }
                  if all(credentials.values()):
                      # 签发token第1步:用账号密码得到user对象
                      user = authenticate(**credentials)
                      if user:
                          if not user.is_active:
                              msg = _('User account is disabled.')
                              raise serializers.ValidationError(msg)
                          # 签发token第2步:通过user得到payload,payload包含着用户信息与过期时间
                          payload = jwt_payload_handler(user)
                          # 在视图类中,可以通过 序列化对象.object.get('user'或者'token') 拿到user和token 
                          return {
                              # 签发token第3步:通过payload签发出token
                              'token': jwt_encode_handler(payload),
                              'user': user
                          }
                      else:
                          msg = _('Unable to log in with provided credentials.')
                          raise serializers.ValidationError(msg)
                  else:
                      msg = _('Must include "{username_field}" and "password".')
                      msg = msg.format(username_field=self.username_field)
                      raise serializers.ValidationError(msg)
              手动签发token逻辑
              # 1)通过username、password得到user对象
              # 2)通过user对象生成payload:jwt_payload_handler(user) => payload
              #       from rest_framework_jwt.serializers import jwt_payload_handler
              # 3)通过payload签发token:jwt_encode_handler(payload) => token
              #       from rest_framework_jwt.serializers import jwt_encode_handler

              校验token

              源码入口
              # 前提:访问一个配置了jwt认证规则的视图类,就需要提交认证字符串token,在认证类中完成token的校验
              
              # 1)rest_framework_jwt.authentication.JSONWebTokenAuthentication 的 父类 BaseJSONWebTokenAuthentication 的 authenticate 方法
              #       请求头拿认证信息jwt-token => 通过反爬小规则确定有用的token => payload => user
              核心源码:rest_framework_jwt.authentication.BaseJSONWebTokenAuthentication的authenticate(self, request)方法
              def authenticate(self, request):
                  """
                  Returns a two-tuple of `User` and token if a valid signature has been
                  supplied using JWT-based authentication.  Otherwise returns `None`.
                  """
                  # 带有反爬小规则的获取token:前台必须按 "jwt token字符串" 方式提交
                  # 校验user第1步:从请求头 HTTP_AUTHORIZATION 中拿token,并提取
                  jwt_value = self.get_jwt_value(request)
                  # 游客
                  if jwt_value is None:
                      return None
                  # 校验
                  try:
                      # 校验user第2步:token => payload
                      payload = jwt_decode_handler(jwt_value)
                  except jwt.ExpiredSignature:
                      msg = _('Signature has expired.')
                      raise exceptions.AuthenticationFailed(msg)
                  except jwt.DecodeError:
                      msg = _('Error decoding signature.')
                      raise exceptions.AuthenticationFailed(msg)
                  except jwt.InvalidTokenError:
                      raise exceptions.AuthenticationFailed()
                  # 校验user第3步:token => payload
                  user = self.authenticate_credentials(payload)
              
                  return (user, jwt_value)
              手动校验token逻辑
              # 1)从请求头中获取token
              # 2)根据token解析出payload:jwt_decode_handler(token) => payloay
              #       from rest_framework_jwt.authentication import jwt_decode_handler
              # 3)根据payload解析出user:self.authenticate_credentials(payload) => user
              #       继承drf-jwt的BaseJSONWebTokenAuthentication,拿到父级的authenticate_credentials方法

              案例:实现多方式登陆签发token

              models.py
              from django.db import models
              
              from django.contrib.auth.models import AbstractUser
              class User(AbstractUser):
                  mobile = models.CharField(max_length=11, unique=True)
              
                  class Meta:
                      db_table = 'api_user'
                      verbose_name = '用户表'
                      verbose_name_plural = verbose_name
              
                  def __str__(self):
                      return self.username
              serializers.py
              from rest_framework import serializers
              from . import models
              import re
              
              # 拿到前台token的两个函数: user => payload => 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_jwt.serializers import jwt_payload_handler
              from rest_framework_jwt.serializers import jwt_encode_handler
              
              
              # 1) 前台提交多种登录信息都采用一个key,所以后台可以自定义反序列化字段进行对应
              # 2) 序列化类要处理序列化与反序列化,要在fields中设置model绑定的Model类所有使用到的字段
              # 3) 区分序列化字段与反序列化字段 read_only | write_only
              # 4) 在自定义校验规则中(局部钩子、全局钩子)校验数据是否合法、确定登录的用户、根据用户签发token
              # 5) 将登录的用户与签发的token保存在序列化类对象中
              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 = {
                          'username': {
                              'read_only': True
                          },
                          'mobile': {
                              'read_only': True
                          },
                          'email': {
                              'read_only': True
                          },
                      }
              
                  def validate(self, attrs):
                      usr = attrs.get('usr')
                      pwd = attrs.get('pwd')
              
                      # 多方式登录:各分支处理得到该方式下对应的用户
                      if re.match(r'[email protected]+', 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()
              
                      # 签发:得到登录用户,签发token并存储在实例化对象中
                      if user_obj and user_obj.check_password(pwd):
                          # 签发token,将token存放到 实例化类对象的token 名字中
                          payload = jwt_payload_handler(user_obj)
                          token = jwt_encode_handler(payload)
                          # 将当前用户与签发的token都保存在序列化对象中
                          self.user = user_obj
                          self.token = token
                          return attrs
              
                      raise serializers.ValidationError({'data': '数据有误'})
              views.py
              #实现多方式登陆签发token:账号、手机号、邮箱等登陆
              # 1) 禁用认证与权限组件
              # 2) 拿到前台登录信息,交给序列化类
              # 3) 序列化类校验得到登录用户与token存放在序列化对象中
              # 4) 取出登录用户与token返回给前台
              import re
              from . import serializers, models
              from utils.response import APIResponse
              
              from rest_framework_jwt.serializers import jwt_payload_handler
              from rest_framework_jwt.serializers import jwt_encode_handler
              
              class LoginAPIView(APIView):
                  # 1) 禁用认证与权限组件
                  authentication_classes = []
                  permission_classes = []
                  def post(self, request, *args, **kwargs):
                      # 2) 拿到前台登录信息,交给序列化类,规则:账号用usr传,密码用pwd传
                      user_ser = serializers.UserModelSerializer(data=request.data)
                      # 3) 序列化类校验得到登录用户与token存放在序列化对象中
                      user_ser.is_valid(raise_exception=True)
                      # 4) 取出登录用户与token返回给前台
                      return APIResponse(token=user_ser.token, results=serializers.UserModelSerializer(user_ser.user).data)
              
                  # "一根筋" 思考方式:所有逻辑都在视图类中处理
                  def my_post(self, request, *args, **kwargs):
                      usr = request.data.get('usr')
                      pwd = request.data.get('pwd')
                      if re.match(r'[email protected]+', 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):
                          payload = jwt_payload_handler(user_obj)
                          token = jwt_encode_handler(payload)
                          return APIResponse(results={'username': user_obj.username}, token=token)
                      return APIResponse(data_msg='不可控错误')

              案例:自定义认证反爬规则的认证类

              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 = jwt_decode_handler(token)
                      except jwt.ExpiredSignature:
                          raise AuthenticationFailed('token已过期')
                      except:
                          raise AuthenticationFailed('非法用户')
                      # payload => user
                      user = self.authenticate_credentials(payload)
              
                      return (user, token)
              
                  # 自定义校验规则:auth token jwt,auth为前盐,jwt为后盐
                  def parse_jwt_token(self, jwt_token):
                      tokens = jwt_token.split()
                      if len(tokens) != 3 or tokens[0].lower() != 'auth' or tokens[2].lower() != 'jwt':
                          return None
                      return tokens[1]
              views.py
              from rest_framework.views import APIView
              from utils.response import APIResponse
              # 必须登录后才能访问 - 通过了认证权限组件
              from rest_framework.permissions import IsAuthenticated
              # 自定义jwt校验规则
              from .authentications import JWTAuthentication
              class UserDetail(APIView):
                  authentication_classes = [JWTAuthentication]
                  permission_classes = [IsAuthenticated]
                  def get(self, request, *args, **kwargs):
                      return APIResponse(results={'username': request.user.username})

              admin使用自定义User表:新增用户密码密文

              from django.contrib import admin
              from . import models
              
              # 自定义User表,admin后台管理,采用密文密码
              from django.contrib.auth.admin import UserAdmin
              
              class MyUserAdmin(UserAdmin):
                  add_fieldsets = (
                      (None, {
                          'classes': ('wide',),
                          'fields': ('username', 'password1', 'password2', 'mobile', 'email'),
                      }),
                  )
              
              admin.site.register(models.User, MyUserAdmin)

              群查接口各种筛选组件数据准备

              models.py
              class Car(models.Model):
                  name = models.CharField(max_length=16, unique=True, verbose_name='车名')
                  price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='价格')
                  brand = models.CharField(max_length=16, verbose_name='品牌')
              
                  class Meta:
                      db_table = 'api_car'
                      verbose_name = '汽车表'
                      verbose_name_plural = verbose_name
              
                  def __str__(self):
                      return self.name
              admin.py
              admin.site.register(models.Car)
              serializers.py
              class CarModelSerializer(serializers.ModelSerializer):
                  class Meta:
                      model = models.Car
                      fields = ['name', 'price', 'brand']
              views.py
              # Car的群查接口
              from rest_framework.generics import ListAPIView
              
              class CarListAPIView(ListAPIView):
                  queryset = models.Car.objects.all()
                  serializer_class = serializers.CarModelSerializer
              urls.py
              url(r'^cars/$', views.CarListAPIView.as_view()),

              drf搜索过滤组件

              views.py
              from rest_framework.generics import ListAPIView
              
              # 第一步:drf的SearchFilter - 搜索过滤
              from rest_framework.filters import SearchFilter
              
              class CarListAPIView(ListAPIView):
                  queryset = models.Car.objects.all()
                  serializer_class = serializers.CarModelSerializer
              
                  # 第二步:局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)
                  filter_backends = [SearchFilter]
              
                  # 第三步:SearchFilter过滤类依赖的过滤条件 => 接口:/cars/?search=...
                  search_fields = ['name', 'price']
                  # eg:/cars/?search=1,name和price中包含1的数据都会被查询出

              drf排序过滤组件

              views.py
              from rest_framework.generics import ListAPIView
              
              # 第一步:drf的OrderingFilter - 排序过滤
              from rest_framework.filters import OrderingFilter
              
              class CarListAPIView(ListAPIView):
                  queryset = models.Car.objects.all()
                  serializer_class = serializers.CarModelSerializer
              
                  # 第二步:局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)
                  filter_backends = [OrderingFilter]
              
                  # 第三步:OrderingFilter过滤类依赖的过滤条件 => 接口:/cars/?ordering=...
                  ordering_fields = ['pk', 'price']
                  # eg:/cars/?ordering=-price,pk,先按price降序,如果出现price相同,再按pk升序

              drf基础分页组件

              pahenations.py
              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'
                  # 用户自定义一页显示的条数最大限制:数值超过5也只显示5条
                  max_page_size = 5
              views.py
              from rest_framework.generics import ListAPIView
              
              class CarListAPIView(ListAPIView):
                  # 如果queryset没有过滤条件,就必须 .all(),不然分页会出问题
                  queryset = models.Car.objects.all()
                  serializer_class = serializers.CarModelSerializer
                  
                  # 分页组件 - 给视图类配置分页类即可 - 分页类需要自定义,继承drf提供的分页类即可
                  pagination_class = pagenations.MyPageNumberPagination
              相关文章
              相关标签/搜索
              香港蓝月亮精选免费资料大全管家婆王中王鉄算盘开奖结果2019开奖记录结果查询香港马会开奖结果历史纪录在线查询 隆德县| 乳山市| 昌都县| 鸡东县| 芮城县| 白玉县| 土默特左旗| 辽阳县| 安岳县| 乌苏市| 彰化县| 泌阳县| 五常市| 桦南县| 墨玉县| 洮南市| 灵武市| 郑州市| 特克斯县| 朝阳市| 赤壁市| 都江堰市| 东光县| 嘉善县| 三门县| 清流县| 临江市| 北流市| 科尔| 万宁市| 梁河县| 乌兰浩特市| 桂平市| 平湖市| 灵璧县| 宝坻区| 阆中市| 沁阳市| 曲周县| 张家界市| 沂南县| 高碑店市| 都匀市| 二手房| 新源县| 应用必备| 许昌县| 政和县| 南平市| 长丰县| 灵寿县| 民勤县| 仁化县| 莎车县| 桂东县| 泸西县| 环江| 临漳县| 西平县| 清丰县| 衡阳市| 泰和县| 府谷县| 长丰县| 年辖:市辖区| 河曲县| 丽水市| 江孜县| 伊金霍洛旗| 桂林市| 峨山| 克什克腾旗| 仪陇县| 三原县| 澎湖县| 沙雅县| 裕民县| 抚州市| 岳普湖县| 屯昌县| 固始县| 海晏县| 玉山县| 鹤峰县| 施秉县| 兴仁县| 遂平县| 奉贤区| 双江| 大兴区| 剑阁县| 长丰县| 盐池县| 德庆县| 宜兰县| 贡山| 淳安县| 获嘉县| 枣阳市| 上蔡县| 东宁县| 安多县| 宜城市| 麦盖提县| 乌审旗| 来宾市| 灵寿县| 大足县| 安平县| 同江市| 阜南县| 怀安县| 都兰县| 腾冲县| 武胜县| 长丰县| 达尔| 泰和县| 成安县| 遂溪县| 易门县| 博兴县| 日喀则市| 郎溪县| 石首市| 团风县| 广宗县| 孝昌县| 勃利县| 洛扎县| 醴陵市| 喀什市| 山东省| 舟山市| 潍坊市| 桃园县| 曲周县| 永定县| 襄樊市| 乐东| 和田市| 泊头市| 桃园县| 怀集县| 沁源县| 嘉祥县| 五寨县| 汨罗市| 明溪县| 佛坪县| 威海市| 乌兰县| 香格里拉县| 长泰县| 青岛市| 法库县| 彭阳县| 醴陵市| 和顺县| 宁乡县| 囊谦县| 磐石市| 新田县| 永德县| 浪卡子县| 精河县| 宜兰市| 丰镇市| 平顺县| 木兰县| 平安县| 罗甸县| 大冶市| 伊金霍洛旗| 乌拉特前旗| 兴仁县| 乐业县| 于田县| 深水埗区| 吉安县| 宁海县| 西乌珠穆沁旗| 伊金霍洛旗| 九寨沟县| 焦作市| 剑阁县| 襄城县| 东至县| 浦县| 阿拉尔市| 当阳市| 建阳市| 山阳县| 裕民县| 海门市| 集贤县| 闻喜县| 阿克陶县| 于田县| 汝州市| 伊通| 阿合奇县| 深水埗区| 莫力| 东城区| 华容县| 合肥市| 琼海市| 丰都县| 道孚县| 岑溪市| 上杭县| 沛县| 庆元县| 洛川县| 抚松县| 建宁县| 鄂伦春自治旗| 清丰县| 溧阳市| 临高县| 特克斯县| 周至县| 宁南县| 惠来县| 云梦县| 鄂托克旗| 潼关县| 淳安县| 边坝县| 海兴县| 察隅县| 积石山| 灵台县| 沿河| 南川市| 沂南县| 高淳县| 京山县| 武强县| 社会| 通河县| 西充县| 运城市| 京山县| 青川县| 尚志市| 包头市| 安平县| 三原县| 溧阳市| 成都市| 高雄县| 平阴县| 邛崃市| 顺平县| 金湖县| 类乌齐县| 锡林郭勒盟| 潞西市| 抚宁县| 克东县| 本溪市| 韩城市| 渑池县| 尚义县| 和静县| 福泉市| 华亭县| 新竹市| 龙州县| 英吉沙县| 饶阳县| 益阳市| 庄浪县| 汪清县| 安乡县| 观塘区| 拜城县| 勐海县| 特克斯县| 麻江县| 石城县| 满洲里市| 彭山县| 阿鲁科尔沁旗| 正宁县| 新兴县| 衢州市| 曲麻莱县| 潮安县| 北流市| 安宁市| 镇原县| 县级市| 东乡县| 澜沧| 星子县| 台东市| 墨竹工卡县| 庄浪县| 宝应县| 琼结县| 孙吴县| 灵宝市| 合山市| 六枝特区| 马关县| 巧家县| 普格县| 田阳县| 台前县| 溧阳市| 阿拉善右旗| 朝阳县| 佛教| 奉化市| 高陵县| 万全县| 新安县| 都江堰市| 峨山| 乌苏市| 手机| 思南县| 来凤县| 金坛市| 威宁| 农安县| 平罗县| 许昌市| 喀喇沁旗| 获嘉县| 岑巩县| 久治县| 孟村| 安化县| 新宁县| 广安市| 大渡口区| 寻乌县| 阿尔山市| 柳江县| 建湖县| 临夏县| 梓潼县| 霍城县| 农安县| 雅安市| 五寨县| 泾源县| 西贡区| 布尔津县| 屯门区| 曲阳县| 石嘴山市| 丹巴县| 南川市| 瑞金市| 特克斯县| 岗巴县| 界首市| 印江| 象山县| 舟曲县| 鸡泽县| 霍州市| 晋城| 南部县| 汶上县| 永川市| 吴川市| 电白县| 逊克县| 衡南县| 东丰县| 区。| 温宿县| 巢湖市| 临沭县| 延庆县| 锡林浩特市| 新丰县| 西畴县| 罗平县| 东至县| 青冈县| 陇南市| 蒲江县| 凤城市| 余庆县| 上饶县| 永宁县| 霍林郭勒市| 屏山县| 博野县| 兴安盟| 松原市| 宜兴市| 砀山县| 尚志市| 女性| 尼玛县| 越西县| 长宁区| 勐海县| 呼伦贝尔市| 葵青区| 安丘市| 永靖县| 城市| 陆良县| 普格县| 大理市| 西乡县| 梓潼县| 蒙山县| 桃江县| 盘锦市| 施秉县| 兖州市| 苏州市| 武汉市| 南丹县| 孟村| 长白| 探索| 乌拉特后旗| 大邑县| 古田县| 商河县| 磐石市| 轮台县| 会理县| 辉南县| 疏附县| 当阳市| 宁陕县| 铜山县| 慈利县| 西青区| 铁力市| 西华县| 阳朔县| 长武县| 凉山| 兴文县| 惠水县| 阆中市| 建湖县| 涞水县| 巴青县| 双牌县| 利辛县| 凤山市| 泗洪县| 禄丰县| 邢台市| 婺源县| 仲巴县| 红桥区| 娱乐| 苍溪县| 鹤壁市| 安国市| 韩城市| 琼海市| 河津市| 若尔盖县| 昆山市| 南城县| 华池县| 怀宁县| 宜宾市| 和田县| 二手房| 天气| 贺州市| 桐柏县| 尚义县| 阳朔县| 海安县| 雅江县| 伊金霍洛旗| 奈曼旗| 弥渡县| 山西省| 闸北区| 固镇县| 齐河县| 西华县| 莱西市| 桐柏县| 井冈山市| 涡阳县| 辽阳县| 海盐县| 阿拉尔市| 贵港市| 滦南县| 瑞金市| 泸溪县| 南川市| 武清区| 巍山| 青神县| 武威市| 玉溪市| 博客| 康马县| 姚安县| 上高县| 灵武市| 高州市| 黄山市| 和硕县| 西华县| 永德县| 三河市| 郓城县| 黔西| 紫云| 嘉义市| 苏尼特右旗| 平塘县| 锦屏县| 平乐县| 岱山县| 渭南市| 张家港市| 特克斯县| 丹江口市| 葫芦岛市| 西乡县| 邯郸市| 绥化市| 黄石市| 大姚县| 怀化市| 汝南县| 石台县| 逊克县| 峨山| 巩义市| 浮梁县| 北川| 奉贤区| 德庆县| 五原县| 梁山县| 潮州市| 日喀则市| 保亭| 呼伦贝尔市| 子洲县| 彩票| 和静县| 延安市| 石渠县| 葫芦岛市| 固安县| 巨野县| 图木舒克市| 保山市| 睢宁县| 南部县| 河东区| 临西县| 鄂托克前旗| 天柱县| 中宁县| 江川县| 玉山县| 集安市| 普定县| 安陆市| 宁国市| 正定县| 怀集县| 资讯| 东阿县| 紫云| 宣化县| 浠水县| 英山县| 德化县| 政和县| 高碑店市| 麻阳| 若尔盖县| 长武县| 淮滨县| 右玉县| 玉树县| 邓州市| 拉萨市| 象山县| 平武县| 大城县| 安达市| 潜江市| 吉首市| 新密市| 郓城县| 东阳市| 泾川县| 甘孜县| 富裕县| 云浮市| 汾西县| 高安市| 蒲城县| 襄汾县| 广丰县| 扶风县| http://www.jx1870deliverv.fun http://wap.jx1870accessv.fun http://3g.jx1870diskv.fun http://3g.jx1870casev.fun http://wap.jx1870castv.fun http://jx1870auditv.fun http://wap.jx1870confirzv.fun http://wap.jx1870boxv.fun http://m.jx1870bookv.fun http://3g.jx1870cozparev.fun http://wap.jx1870editv.fun http://3g.jx1870drawv.fun http://jx1870azountv.fun http://wap.jx1870allowv.fun http://m.jx1870censusv.fun http://3g.jx1870concernv.fun http://wap.jx1870carryv.fun http://3g.jx1870chipv.fun