drf之文档生成和jwt(代码片段)

henry121 henry121     2022-12-05     239

关键词:

1 自定制频率

# 自定制频率类,需要写两个方法
	-# 判断是否限次:没有限次可以请求True,限次了不可以请求False
    	def allow_request(self, request, view):
    -# 限次后调用,显示还需等待多长时间才能再访问,返回等待的时间seconds
    	def wait(self):
            
# 代码
import time
class IPThrottle():
    #定义成类属性,所有对象用的都是这个
    VISIT_DIC = 
    def __init__(self):
        self.history_list=[]
    def allow_request(self, request, view):
        ‘‘‘
        #(1)取出访问者ip
        #(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
        #(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
        #(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
        #(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
        ‘‘‘

        ip=request.META.get(‘REMOTE_ADDR‘)
        ctime=time.time()
        if ip not in self.VISIT_DIC:
            self.VISIT_DIC[ip]=[ctime,]
            return True
        self.history_list=self.VISIT_DIC[ip]   #当前访问者时间列表拿出来
        while True:
            if ctime-self.history_list[-1]>60:
                self.history_list.pop() # 把最后一个移除
            else:
                break
        if len(self.history_list)<3:
            self.history_list.insert(0,ctime)
            return True
        else:
            return False

    def wait(self):
        # 当前时间,减去列表中最后一个时间
        ctime=time.time()

        return 60-(ctime-self.history_list[-1])

#全局使用,局部使用

# SimpleRateThrottle源码分析
    def get_rate(self):
        """
        Determine the string representation of the allowed request rate.
        """
        if not getattr(self, ‘scope‘, None):
            msg = ("You must set either `.scope` or `.rate` for ‘%s‘ throttle" %
                   self.__class__.__name__)
            raise ImproperlyConfigured(msg)

        try:
            return self.THROTTLE_RATES[self.scope]  # scope:‘user‘ => ‘3/min‘
        except KeyError:
            msg = "No default throttle rate set for ‘%s‘ scope" % self.scope
            raise ImproperlyConfigured(msg)
    def parse_rate(self, rate):
        """
        Given the request rate string, return a two tuple of:
        <allowed number of requests>, <period of time in seconds>
        """
        if rate is None:
            return (None, None)
        #3  mmmmm
        num, period = rate.split(‘/‘)  # rate:‘3/min‘
        num_requests = int(num)
        duration = ‘s‘: 1, ‘m‘: 60, ‘h‘: 3600, ‘d‘: 86400[period[0]]
        return (num_requests, duration)
    def allow_request(self, request, view):
        if self.rate is None:
            return True
        #当前登录用户的ip地址
        self.key = self.get_cache_key(request, view)  # key:‘throttle_user_1‘
        if self.key is None:
            return True

        # 初次访问缓存为空,self.history为[],是存放时间的列表
        self.history = self.cache.get(self.key, [])
        # 获取一下当前时间,存放到 self.now
        self.now = self.timer()

        # Drop any requests from the history which have now passed the
        # throttle duration

        # 当前访问与第一次访问时间间隔如果大于60s,第一次记录清除,不再算作一次计数
        # 10 20 30 40
        # self.history:[10:23,10:55]
        # now:10:56
        while self.history and  self.now - self.history[-1] >= self.duration:
            self.history.pop()

        # history的长度与限制次数3进行比较
        # history 长度第一次访问0,第二次访问1,第三次访问2,第四次访问3失败
        if len(self.history) >= self.num_requests:
            # 直接返回False,代表频率限制了
            return self.throttle_failure()

        # history的长度未达到限制次数3,代表可以访问
        # 将当前时间插入到history列表的开头,将history列表作为数据存到缓存中,key是throttle_user_1,过期时间60s
        return self.throttle_success()

2 自动生成接口文档

# 1 安装:pip install coreapi

# 2 在路由中配置
	from rest_framework.documentation import include_docs_urls
    urlpatterns = [
        ...
        path(‘docs/‘, include_docs_urls(title=‘站点页面标题‘))
    ]
#3 视图类:自动接口文档能生成的是继承自APIView及其子类的视图。
	-1 ) 单一方法的视图,可直接使用类视图的文档字符串,如
        class BookListView(generics.ListAPIView):
            """
            返回所有图书信息.
            """
    -2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如
        class BookListCreateView(generics.ListCreateAPIView):
            """
            get:
            返回所有图书信息.
            post:
            新建图书.
            """
    -3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分,如
        class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
        """
        list:
        返回图书列表数据
        retrieve:
        返回图书详情数据
        latest:
        返回最新的图书数据
        read:
        修改图书的阅读量
        """

3 JWT

jwt=Json Web token
#原理
"""
1)jwt分三段式:头.体.签名 (head.payload.sgin)
2)头和体是可逆加密,让服务器可以反解出user对象;签名是不可逆加密,保证整个token的安全性的
3)头体签名三部分,都是采用json格式的字符串,进行加密,可逆加密一般采用base64算法,不可逆加密一般采用hash(md5)算法
4)头中的内容是基本信息:公司信息、项目组信息、token采用的加密方式信息

	"company": "公司信息",
	...

5)体中的内容是关键信息:用户主键、用户名、签发时客户端信息(设备号、地址)、过期时间

	"user_id": 1,
	...

6)签名中的内容时安全信息:头的加密结果 + 体的加密结果 + 服务器不对外公开的安全码 进行md5加密

	"head": "头的加密字符串",
	"payload": "体的加密字符串",
	"secret_key": "安全码"

"""

校验
"""
1)将token按 . 拆分为三段字符串,第一段 头加密字符串 一般不需要做任何处理
2)第二段 体加密字符串,要反解出用户主键,通过主键从User表中就能得到登录用户,过期时间和设备信息都是安全信息,确保token没过期,且时同一设备来的
3)再用 第一段 + 第二段 + 服务器安全码 不可逆md5加密,与第三段 签名字符串 进行碰撞校验,通过后才能代表第二段校验得到的user对象就是合法的登录用户
"""

drf项目的jwt认证开发流程(重点)
"""
1)用账号密码访问登录接口,登录接口逻辑中调用 签发token 算法,得到token,返回给客户端,客户端自己存到cookies中

2)校验token的算法应该写在认证类中(在认证类中调用),全局配置给认证组件,所有视图类请求,都会进行认证校验,所以请求带了token,就会反解出user对象,在视图类中用request.user就能访问登录的用户

注:登录接口需要做 认证 + 权限 两个局部禁用
"""

# 第三方写好的  django-rest-framework-jwt
# 安装pip install djangorestframework-jwt

# 新建一个项目,继承AbstractUser表()

# 创建超级用户

# 简单使用
 #urls.py
    from rest_framework_jwt.views import ObtainJSONWebToken,VerifyJSONWebToken,RefreshJSONWebToken,obtain_jwt_token
    path(‘login/‘, obtain_jwt_token),

3.1 自定制auth认证类

from rest_framework_jwt.authentication import BaseAuthentication,BaseJSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.authentication import get_authorization_header,jwt_get_username_from_payload
from rest_framework import exceptions
class MyToken(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        jwt_value=str(request.META.get(‘HTTP_AUTHORIZATION‘))
        # 认证
        try:
            payload = jwt_decode_handler(jwt_value)

        except Exception:
            raise exceptions.AuthenticationFailed("认证失败")
        user=self.authenticate_credentials(payload)
        return user,None
    

3.2 控制用户登录后才能访问,和不登录就能访问

# 1 控制用户登录后才能访问,和不登录就能访问
from rest_framework.permissions import IsAuthenticated
class OrderAPIView(APIView):# 登录才能
    authentication_classes = [JSONWebTokenAuthentication,]
    # 权限控制
    permission_classes = [IsAuthenticated,]
    def get(self,request,*args,**kwargs):
        return Response(‘这是订单信息‘)


class UserInfoAPIView(APIView):# 不登录就可以
    authentication_classes = [JSONWebTokenAuthentication,]
    # 权限控制
    # permission_classes = [IsAuthenticated,]
    def get(self,request,*args,**kwargs):
        return Response(‘UserInfoAPIView‘)

3.3 控制登录接口返回的数据格式

# 2 控制登录接口返回的数据格式
	-第一种方案,自己写登录接口
    -第二种写法,用内置,控制登录接口返回的数据格式
    	-jwt的配置信息中有这个属性
    	    ‘JWT_RESPONSE_PAYLOAD_HANDLER‘:
    ‘rest_framework_jwt.utils.jwt_response_payload_handler‘,
    	-重写jwt_response_payload_handler,配置成咱们自己的

3.4 自定义基于jwt的权限类

# 3 自定义基于jwt的权限类
from rest_framework.authentication import BaseAuthentication  # 基于它
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication # 基于它
from rest_framework.exceptions import AuthenticationFailed
# from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.utils import jwt_decode_handler # 跟上面是一个
import jwt

from api import models
# class MyJwtAuthentication(BaseAuthentication):
#     def authenticate(self, request):
#         jwt_value=request.META.get(‘HTTP_AUTHORIZATION‘)
#         if jwt_value:
#             try:
#             #jwt提供了通过三段token,取出payload的方法,并且有校验功能
#                 payload=jwt_decode_handler(jwt_value)
#             except jwt.ExpiredSignature:
#                 raise AuthenticationFailed(‘签名过期‘)
#             except jwt.InvalidTokenError:
#                 raise AuthenticationFailed(‘用户非法‘)
#             except Exception as e:
#                 # 所有异常都会走到这
#                 raise AuthenticationFailed(str(e))
#             # 因为payload就是用户信息的字典
#             print(payload)
#             # return payload, jwt_value
#             # 需要得到user对象,
#             # 第一种,去数据库查
#             # user=models.User.objects.get(pk=payload.get(‘user_id‘))
#             # 第二种不查库
#             user=models.User(id=payload.get(‘user_id‘),username=payload.get(‘username‘))
#             return user,jwt_value
#         # 没有值,直接抛异常
#         raise AuthenticationFailed(‘您没有携带认证信息‘)


class MyJwtAuthentication(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        jwt_value=request.META.get(‘HTTP_AUTHORIZATION‘)
        if jwt_value:
            try:
            #jwt提供了通过三段token,取出payload的方法,并且有校验功能
                payload=jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                raise AuthenticationFailed(‘签名过期‘)
            except jwt.InvalidTokenError:
                raise AuthenticationFailed(‘用户非法‘)
            except Exception as e:
                # 所有异常都会走到这
                raise AuthenticationFailed(str(e))
            user=self.authenticate_credentials(payload)
            return user,jwt_value
        # 没有值,直接抛异常
        raise AuthenticationFailed(‘您没有携带认证信息‘)

3.5 手动签发token(多方式登录)

# 使用用户名,手机号,邮箱,都可以登录#
# 前端需要传的数据格式

"username":"lqz/1332323223/33@qq.com",
"password":"lqz12345"

# 视图
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin, ViewSet

from app02 import ser
class Login2View(ViewSet):  # 跟上面完全一样
    def login(self, request, *args, **kwargs):
        # 1 需要 有个序列化的类
        login_ser = ser.LoginModelSerializer(data=request.data,context=‘request‘:request)
        # 2 生成序列化类对象
        # 3 调用序列号对象的is_validad
        login_ser.is_valid(raise_exception=True)
        token=login_ser.context.get(‘token‘)
        # 4 return
        return Response(‘status‘:100,‘msg‘:‘登录成功‘,‘token‘:token,‘username‘:login_ser.context.get(‘username‘))
    
# 序列化类
from rest_framework import serializers
from api import models
import re
from rest_framework.exceptions import ValidationError

from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
class LoginModelSerializer(serializers.ModelSerializer):
    username=serializers.CharField()  # 重新覆盖username字段,数据中它是unique,post,认为你保存数据,自己有校验没过
    class Meta:
        model=models.User
        fields=[‘username‘,‘password‘]

    def validate(self, attrs):

        print(self.context)

        # 在这写逻辑
        username=attrs.get(‘username‘) # 用户名有三种方式
        password=attrs.get(‘password‘)
        # 通过判断,username数据不同,查询字段不一样
        # 正则匹配,如果是手机号
        if re.match(‘^1[3-9][0-9]9$‘,username):
            user=models.User.objects.filter(mobile=username).first()
        elif re.match(‘^.+@.+$‘,username):# 邮箱
            user=models.User.objects.filter(email=username).first()
        else:
            user=models.User.objects.filter(username=username).first()
        if user: # 存在用户
            # 校验密码,因为是密文,要用check_password
            if user.check_password(password):
                # 签发token
                payload = jwt_payload_handler(user)  # 把user传入,得到payload
                token = jwt_encode_handler(payload)  # 把payload传入,得到token
                self.context[‘token‘]=token
                self.context[‘username‘]=user.username
                return attrs
            else:
                raise ValidationError(‘密码错误‘)
        else:
            raise ValidationError(‘用户不存在‘)

3.6 jwt的配置参数

# jwt的配置
import datetime
JWT_AUTH=
    ‘JWT_RESPONSE_PAYLOAD_HANDLER‘:‘app02.utils.my_jwt_response_payload_handler‘,
    ‘JWT_EXPIRATION_DELTA‘: datetime.timedelta(days=7), # 过期时间,手动配置

drf9(代码片段)

今日内容概要接口文档jwt介绍和原理drf-jwt快速使用定制返回格式jwt的认证类今日内容详细接口文档做前后端分离项目的时候通常需要写接口文档接口文档如何编写的方式 1.使用wordmd等编写接口文档 2.使用第三方平台编写我们的... 查看详情

drf之jwt傻瓜式启动说明书(代码片段)

DRF之jwt使用说明书jwt介绍JsonWebToken如何获取token先创建一张用户表,要想使用jwt,必须使用django自带的用户表在models.py中写一个用户类,导入、继承AbstractUser在Terminal中做数据库迁移,createsuperuser创建超级用户在路由中导入jwt的... 查看详情

drf生成接口文档(代码片段)

RESTframework可以自动帮助我们生成接口文档。接口文档以网页的方式呈现。自动接口文档能生成的是继承自APIView及其子类的视图。一.安装依赖RESTframewrok生成接口文档需要coreapi库的支持。pipinstallcoreapi二设置接口文档访问路径在... 查看详情

drf框架生成接口文档(代码片段)

一、简介生成API文档平台自动生成测试代码支持接口测试二、安装coreapi(必须)Pygments(可选)MarkDown(可选)pipinstall-ihttps://pypi.douban.com/simplecoreapipipinstall-ihttps://pypi.douban.com/simplePygmentspipinstall-ihttps://pypi.douban.com 查看详情

drf?jwt自动签发与手动签发(代码片段)

目录一、自动签发二、手动签发一、自动签发urlsfromrest_framework_jwt.viewsimportobtain_jwt_token#使用jwt自带的登录视图urlpatterns=[path(‘login/‘,obtain_jwt_token),]settingsimportdatetimeJWT_AUTH=#配置响应格式,必须和自动签发使用‘JWT_RESPONSE_PAYL 查看详情

drf之自动生成接口文档

自动生成接口文档(3星)前言流程:后端人员写好接口,编写接口文档,给前端人员看,前端人员依照接口文档开发公司里的主流:后端,使用world,md写,提到git上公司有接口平台,后端开发在接口平台录入(yapi,第三方),可... 查看详情

drf框架之用户登录状态保持(代码片段)

   本篇主要介绍用户状态保持的两种的方案--session和jwt_token,以及这两种方案的实现方式,及优缺点对比。  引入:HTTP协议是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码进行用户认证... 查看详情

drf-jwt(代码片段)

DRF-JWT一、JWTJWT全称:jsonwebtoken,作用:将原始的数据json加密成字符串,通过后台将加密的字符串给前台存储(token)格式:三段式,头.载荷.签名,头和载荷都是采用base34可逆加密,签名采用md5不可逆加密头(基础信息,也可以为空):... 查看详情

drf-jwt认证(代码片段)

1JWT认证在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用JsonWebToken(本质就是token)认证机制。#Jsonwebtoken(JWT),是为了在网络应用环境间传递声明而执行的... 查看详情

drf框架之modelserializer序列化器(代码片段)

...rializer与常规的Serializer相同,但提供了:基于模型类自动生成一系列字段基于模型类自动为Serializer生成validators,比如unique_together包含默认的create()和update()的实现在使用ModelSerializer序列化器时,我们只需要定义好序列化器类,并... 查看详情

drf框架——drf-jwt手动签发与校验过滤组件筛选组件排序组件分页组件(代码片段)

自定义drf-jwt手动签发和校验签发token源码入口前提:给一个局部禁用了所有认证与权限的视图类发送用户信息得到token,其实就是登录接口,不然进不了登录页面获取提交的username和password1)rest_framework_jwt.views.ObtainJSONWebToken的父... 查看详情

drf认证组件权限组件jwt认证签发jwt框架使用(代码片段)

目录一、注册接口urls.pyviews.pyserializers.py二、登录接口三、用户中心接口(权限校验)urls.pyviews.pyserializers.py四、图书资源接口urls.pyviews.pyserializers.py五、认证组件重点自定义认证类六、权限组件重点自定义权限类七、jwt认证示意... 查看详情

drf之版本控制认证和权限组件(代码片段)

一、版本控制组件1、为什么要使用版本控制首先我们开发项目是有多个版本的当我们项目越来越更新,版本就越来越多,我们不可能新的版本出了,以前旧的版本就不进行维护了像bootstrap有2、3、4版本的,每个版本都有它对应... 查看详情

vue_drf之支付宝接口(代码片段)

  一、配置  1,生成应用秘钥和公钥  下载对应系统的秘钥生成工具:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105971&docType=1    2,配置秘钥  2.1把我们生成的应用公钥放到支付宝上,把支付宝公钥复制... 查看详情

drf-jwt手动签发与校验与drf小组件(代码片段)

签发token源码入口"""前提:给一个局部禁用了所有认证与权限的视图类发送用户信息得到token,其实就是登陆接口1)rest_framework_jwt.views.ObtainJSONWebToken的父类JSONWebTokenAPIView的post方法接受有username,password的post请求2)post方法将请求数据交... 查看详情

drf-jwt认证组件权限组件频率组件的使用(代码片段)

目录drf-jwt认证组件、权限组件、频率组件的使用认证组件权限组件频率组件drf-jwt签发token源码分析自定义签发token实现多方式登录源码分析多方式登陆签发token实例频率组件自定义频率类drf-jwt认证组件、权限组件、频率组件的使... 查看详情

jwt(代码片段)

...息加密.当前的登陆用户与过期时间加密.头部+载荷+秘钥生成不可逆加密校验token:头部可校验也可以不校验,载荷校验出用户与过期时间,头部+载荷+秘钥完成碰撞检测校验token是否被篡改"&q 查看详情

drf版本认证权限限制解析器和渲染器(代码片段)

目录一.DRF之版本控制为什么要有版本控制?DRF提供的版本控制方案版本的使用全局配置局部配置(使用较少)二.DRF之认证内置的认证步骤三.DRF之权限1.自定义一个权限类2.权限局部配置3.权限全局配置四.DRF之限制1.使用自定义限制类... 查看详情