昨日回顾

# 1 认证类的执行流程---》源码分析
	-请求进来---》路由匹配成功----》执行path('test/', view.BookView.as_view()),--->继承了APIView----》APIView的as_view()内部的闭包函数view----》这个view中执行了self.dispatch--->APIView的dispatch----》
    def dispatch(self, request, *args, **kwargs):
        # 包装了新的request
        request = self.initialize_request(request, *args, **kwargs)
        。。。
        # 执行3大认证
        self.initial(request, *args, **kwargs)
        # 下面执行视图类的方法
    def initial(self, request, *args, **kwargs):
        # 认证
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)
	def perform_authentication(self, request):
        request.user
 	####### Request 新的Request内部找  user
    @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():  # 上下文管理器----》面试
                self._authenticate()
        return self._user
   ### 核心代码
    def _authenticate(self):
        # self.authenticators---》列表[认证类对象1,认证类对象2]
        # authenticator 是认证类的对象
        for authenticator in self.authenticators:
            try:
                #认证类对象.authenticate   self 是新的request对象
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                #self 是新的request
                # request.user 就是当前登录用户
                # request.auth 一般把token给它
                self.user, self.auth = user_auth_tuple
                return
        self._not_authenticated()
        
  # self.authenticators:是什么时候传入的?执行__init__ 就是在Request初始化的时候传入的
	-在APIView的dispatch的self.initialize_request(request, *args, **kwargs)初始化的,
     return Request(
            request,
            parsers=self.get_parsers(),
         	#在这里传入的
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    -APIView的--get_authenticators()----》return [auth() for auth in self.authentication_classes]
    
    -self.authentication_classes:视图类中配置的一个个的认证类的列表,如果没配,配置文件中,内置配置文件中
    

# 2 权限类的执行流程



# 3 频率类的执行流程

# 4 自己定义了一个频率类,基于BaseThrottle,重写allow_request

# 5 SimpleRateThrottle
	-继承它,写代码少
    -只需要重写get_cache_key和scope类属性,配置文件配置
    -源码:allow_request----》就是咱们上面写的,可扩展性高,好多东西从配置文件取的
    
    
    
# 6 全局异常处理
	-源码中,在3大认证,视图类的方法中如果出错,就会执行:self.handle_exception(exc)
     def handle_exception(self, exc):
        # 去配置文件中找到:EXCEPTION_HANDLER对应的函数,exception_handler
        exception_handler = self.get_exception_handler()
        # exception_handler(exc,context)
        response = exception_handler(exc, context)
        return response
    
    
    -自己再配置文件中配置,以后出了异常,走咱们自己的,有两个参数exc, context
    	-exc错误对象
        -context:上下文,包含 view,request。。。。

当请求进来 ---> 路由匹配成功 ---> 执行可调用对象
执行path('test/',view.BookView.as_view())
---> APIView的dispatch ---去掉csrf--> 原生django的dispatch

image-20230209084630401

执行可调用对象:
path('test/',可调用对象)

可以放置如下可调用对象:

  • 可以放函数的内存地址 ---> 执行APIView的view闭包函数
  • 可以放一个对象 ---> 执行魔法方法__call__

认证

image-20230209084651600

request.user:
image-20230209084456161

request.user()可以加括号调用吗?
实现with上下文管理器 重写两个魔法方法。

核心代码:

image-20230209084849480

self.authenticators:
image-20230209084933644

request对象何时执行__init__?
request对象什么时候初始化的。

image-20230209085025927

initalize_request,在这里传入列表,列表里都是认证类的对象:

image-20230209085107841

使用这个函数获取认证类的对象:

image-20230209085130587

关于认证类的获取:

image-20230209085314315

重新回到_authenticate:
调用认证类的authenticate方法。

image-20230209085611341

后续:
image-20230209095157980

通过认证
image-20230209085436721

认证函数的返回值:

权限

image-20230209085938922

权限第一个没过,后面就不会再走了,因为会抛出一个异常。
image-20230209085852162

频率

image-20230209090508889

  1. 自定义频率类:继承Basethrottle, 重写allow_request.
    认证权限限流 中间件 9.06 28 限流逻辑
  2. SimpleRateThrottle 不太懂
    重写get_cache_keyscope

image-20230209090944232

会对django进行一次封装。

全局异常处理

image-20230209091846051

image-20230209091711648

找到配置文件中对应的函数。

自定义异常处理:
image-20230209091941147

APIview的exception_handler只处理drf的异常。

你给前端详细的报错信息,前端会直接在app上面打印。
服务异常请稍后再试 ---> 接口崩了。

context如何包装?
image-20230209092252367

image-20230209092419615

auth ---》 model --》 表定义。

云闪付app:银联出的云闪付,招商银行付款不成功,10038错误
云闪付客服 ---> 招商银行接口的问题 ---> 招商银行的问题 ---> 云闪付的问题
就是调用付款接口招商银行的问题。

接口文档

# 前后端分离
	-我们做后端,写接口
    -前端做前端,根据接口写app,pc,小程序
    
    -作为后端来讲,我们很清楚,比如登录接口  /api/v1/login/---->post---->username,password 编码方式json----》返回的格式  {code:100,msg:登录成功}
    
    
    -后端人员,接口写完,一定要写接口文档
    
    
# 接口文档如何编写
	-1 使用word,md 编写接口文档
    -2 使用第三方平台,编写我们的接口文档(非常多)---》收费
    	-https://www.showdoc.com.cn/item/index
    -3 公司自己使用第三方开源的搭建的---》Yapi ---》你如果想自己搭建
    	-https://zhuanlan.zhihu.com/p/366025001 
            
    -4 使用drf编写的接口,可以自动生成接口文档
    	-swagger---》drf-yasg---》官方推荐使用
        -coreapi----》咱们讲
    
    
# 使用coreapi自动生成接口文档步骤
	- 1 安装 
    - 2 配置路由
        from rest_framework.documentation import include_docs_urls
        path('docs/', include_docs_urls(title='xx项目接口文档')),
    -3 在视图类,方法上,写注释即可
    	-在类上加注释
        -在类的方法上加注释
        -在序列化类或表模型的字段上加  help_text,required。。。。
    
    
    -4 配置文件配置
    	REST_FRAMEWORK = {
     		'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',

    	}
        
        
   -5 访问地址:http://127.0.0.1:8000/docs
    
    
    
# 接口文档,需要有的东西
	-描述
    -地址
    -请求方式
    -请求编码格式
    -请求数据详解(必填,类型)
    -返回格式案例
    -返回数据字段解释
    -错误码

接口文档编写

-1 使用word,md 编写接口文档 (很多公司在用)
-2 使用第三方软件平台,编写我们的接口文档(非常多)
一般来说收费,不安全
https://showDoc.com.cn
2个人协作免费 --> 5个人收费
-3 公司使用第三方开源的搭建的
YApi ---> 大公司有专业的人搭建

-4 drf自动生成接口文档

示例:

image-20230209100000580

image-20230209100034236

重点:
image-20230209100055183

image-20230209100113350

重点是请求的URL的地址 ---> 千万不能写错
编码格式:

image-20230209100259551

接口文档,需要有的东西:
描述、地址、请求方式、编码格式、请求数据详解、返回数据详解

YApi:
image-20230209100736677

有时间搭建一下:
image-20230209100905119

B站自己开发的接口文档平台。
编写接口文档,是后端的工作之一。

drf自动生成接口文档

image-20230209101513650

image-20230209101537558

官方推荐使用drf-yssg ---> 不好用
-swagger --drf-> drf-yasg
image-20230209101653898

coreapi自动生成文档:
image-20230209102049320

在类方法上写注释:
image-20230209102205913

在配置文件去配置:

image-20230209102224714

查看效果:
image-20230209102533628

会自动生成接口。
如何加注释?
image-20230209102749986

如果类中没有方法,直接加注释:

image-20230209102943477

注释会显示在前端:
image-20230209103019580

序列化类中写:
image-20230209103132460

表模型中写:
image-20230209103155037

image-20230209103315951

还可以直接操作:

image-20230209103341124

python/Django-rest-framework框架/8-drf-自动生成接口文档 | Justin-刘清政的博客 (liuqingzheng.top)

cookies-session-token发展史

不需要做会话的保持。不能记住刚刚是谁发送的请求。
请求来了,就发送给静态页面。无状态 无连接 也是http请求的问题

需要做会话的标识,区分请求是谁 ---> cookies的产生

cookies存在浏览器不安全 ---> cookies + session

cookies和session几乎同时出现。在服务端存放的键值对叫session,在浏览器存放的键值对叫cookies。

服务器需要保存所有人的sessionid,服务器吃不消。

服务器集群的问题11.03 5
集群增加并发量。
image-20230209110540100

image-20230209110644010

解决安全性问题,让客户端来保存。

image-20230209110820936

头 (公司信息) 荷载 (用户信息)--生成--> 签名 ---> token的签发阶段

image-20230209111026651

只要包装的用户Id是安全的就可以了。
我不知道加密方式 和 密钥的情况下 是无法生成签名的。

存在直接获取整个token,来发送请求获取服务器的信息的方法。
----> 爬虫

jwt介绍和原理

# cookie session token 发展史

# Json web token (JWT)  就是web方向token的使用

#JWT的构成 三部分,每部分用 .  分割
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

	- 头:header
    	声明类型,这里是jwt
		声明加密的算法 通常直接使用 HMAC SHA256
        公司信息。。。
    -荷载:payload
    	-存放有效信息的地方
        -过期时间
        -签发时间
        -用户id
        -用户名字。。。
	-签名:signature
    	-第一部分和第二部分通过秘钥+加密方式得到的
        
        

# jwt开发重点
	-登录接口---->签发token
    -认证类-----》jwt认证





#  base64编码和解码

import base64
import json
# dic={'user_id':1,'username':"lqz"}
#
# dic_str=json.dumps(dic)
#
# #把这个字符串使用base64编码
# res=base64.b64encode(dic_str.encode('utf-8'))
# print(res)   #


# 注意:base64编码后,字符长度一定是4的倍数,如果不是,使用  =  补齐,  = 不表示数据
# 解码
res=base64.b64decode('TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ=')
print(res)



# base64 应用场景
'''
1 jwt 使用了base64
2 网络中传输数据,也会经常使用 base64编码
3 网络传输中,有的图片使用base64编码

'''
s=''
res=base64.b64decode(s)
with open('a.png','wb') as f:
    f.write(res)

token签发和认证流程:
image-20230209114136493

头和荷载 ---> 猜加密方式 ---> 还有密钥

社会工程学 ---> 通过其他网站的密码,猜到这个网站的密码

jwt的构成

image-20230209114615539

base64的编码和解码

image-20230209114856123

image-20230209114849942

image-20230209114944620

image-20230209115027493

头。

体包含过期时间:

image-20230209115146706

base64编码字符长度一定是4的倍数,否则会报错:不足需要用=补齐。
image-20230209115319111

=这个字符不存储数据。

image-20230209115439774

网络传输中使用base64
image-20230209115537427

前端需要用base64转换一下。明文的密码只能在自己电脑上被抓到。

图片base64加密:

image-20230209115824909

base64解码,保存到文件:
image-20230209115941814

传输jwt也会进行base64编码。
image-20230209120230964

drf-jwt快速使用

#django+drf 平台开发jwt这套,有两个模块
	-djangorestframework-jwt  ---》一直可以用
    -djangorestframework-simplejwt---》公司用的多---》希望你们试一下
    -自己封装jwt签发和认证
# 使用步骤
    - 1 安装
    - 2 快速签发token---》登录接口,路由中配置
     	path('login/', obtain_jwt_token),
    - 3 使用createsuperuser 创建一个用户 (drf-jwt是基于django的auth用户表进行快速签发)
    - 4postman,向http://127.0.0.1:8000/login/发送post请求,携带username和password 

drf-jwt年久失修。

自己封装jwt签发和认证。

公司用的djangorestframework-simplejwt
image-20230209120651422

老项目 --->不好用 ---> 我重写了

安装drf-jwt

基于auth的user表签发。
image-20230209121141146

image-20230209121221892

image-20230209121352043

image-20230209121405359

image-20230209121452782

image-20230209121436539

密钥使用的是配置文件中的密钥:
image-20230209121536229

定制返回格式

# 以后,如果是基于auth的User表签发token,就可以不自己写了,但是登录接口返回的格式,只有token,不符合公司规范

# 使用步骤
	1 写个函数:jwt_response_payload_handler
        def jwt_response_payload_handler(token, user=None, request=None):
            return {
                'code': 100,
                'msg': '登录成功',
                'token': token,
                'username': user.username
                # 'icon':user.icon
            }
    2 配置一下 ,项目配置文件
    JWT_AUTH = {
    	'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.jwt_response_payload_handler',  
	}
    
    3 使用postman测试,就能看到返回的格式了

基于auth的user表签发token,就可以不用自己写了。

image-20230209122008096

image-20230209122225740

image-20230209122232976

image-20230209122342053

image-20230209122411923

jwt的认证类

# 以后接口要登录后才能访问的使用

	1 在视图类上加一个认证类,一个权限类class BookView(ViewSetMixin, RetrieveAPIView):
    	authentication_classes = [JSONWebTokenAuthentication]
    	permission_classes = [IsAuthenticated]  # 登录用户有权限,不登录用户没权限
	2 postman测试
    	-请求头中key值叫Authorization
        -请求头的value值是:  jwt 有效的token值

jwt提供的登录认证:

image-20230209122828588


判断带没带token 没带不管 带了必须认证
没带身份证开台机子 带了必须满18

image-20230209122948812

控制登录用户的权限。
token带在请求头中:
image-20230209123220403

image-20230209123456963

第一个是jwt提供的认证类 第二个是drf提供的权限类
既然使用jwt认证 那么必须按照别人的要求写。

image-20230209123630893

image-20230209123727141

1 自动生成接口文档试一下 
2 使用drf-jwt快速签发和认证token,定制返回格式 ok
3 使用simplejwt,签发token
4 drf-jwt 登录接口怎么写的
	-它把逻辑写在了序列化类中----》全局钩子中

djangorestframework-simplejwt教程