接口文档 jwt介绍和原理 drf-jwt快速使用 定制返回格式 jwt认证类

回顾

# 认证类的执行流程 ---> 源码分析
	请求进来 ---> 路由匹配成功 ---> 执行path('test/', view.BookView.as_view()), ---> 继承了APIView ---> APIView的as_view()内部的闭包函数view ---> 这个view中执行了self.dispatch ---> APIView的dispatch ---> 这个view中执行了self.dispatch ---> APIView的dispatch --->
  def dispatch(self, request, *args, **kwargs):
    # 包装了新的requset
 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。。。。

接口文档

# 前后端分离
	-我们做后端,写接口
    -前端做前端,根据接口写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的安装及使用

# 使用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
    
    
    
# 接口文档,需要有的东西
	-描述
    -地址
    -请求方式
    -请求编码格式
    -请求数据详解(必填,类型)
    -返回格式案例
    -返回数据字段解释
    -错误码

在类的最顶上加上注释,类下的所有方法都有
image-20230209220828771
在类的方法上加注释,就只要某一个方法有,会把类的注释信息顶掉

def list(self, request, *args, **kwargs):
    """
        查询所有图书方法
        :param request:
        :param args:
        :param kwargs:
        :return: 返回查询所有图书信息
        """

image

在序列化类或表模型的字段上加help_text,required。。。优先显示序列化类中的help_text信息

id= serializers.IntegerField(help_text='书籍id')
 
 
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField(help_text='书籍价格')

image

jwt介绍和原理

# cookie session token 发展史

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

介绍:

JWT认证:在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token(本质就是token)认证机制

构成和工作原理:

1.JWT的构成

JWT就是一段字符串,由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

2.JWT之header

jwt的头部承载两部分信息:

  • 声明类型 这里是jwt
  • 声明机密的算法,通常直接使用HMAC SHA256

完整的头部就像下面这样的JSON

{
  'typ': 'JWT',
  'alg': 'HS256'
}

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

3.JWT之荷载(payload)

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明:公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
  • 私有的声明:私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息

定义一个payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

然后将其进行base64加密,得到JWT的第二部分

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

JWT之签证(signature)

JWT的第三部分是一个签证信息,这个签证信息由三部分组成

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

再者三部分用 . 连接成一个完整的字符串,构成了最终的jwt

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

PS:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了

总结:

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

image-20230209224456475

drf项目的jwt认证开发流程(重点)

1)用账号密码访问登录接口,登录接口逻辑中调用 签发token 算法,得到token,返回给客户端,客户端自己存到cookies中

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

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

补充base64编码解码

#  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)

image-20230209203637938

drf-jwt快速使用

#django+drf 平台开发jwt这套,有两个模块
	-djangorestframework-jwt  ---》一直可以用
	-djangorestframework-simplejwt---》公司用的多---》自己试一下
    -自己封装jwt签发和认证
# 使用步骤
	- 1 安装
  from restframework_jwt.view import obtain_jwt_token
  - 2 快速签发token---》登录接口,路由中配置
    	path('login/', obtain_jwt_token),

  - 3 使用Django自带authuser表用createsuperuser创建超级用户插入一条数据
  - 4  postman,向http://127.0.0.1:8000/login/发送post请求,携带username和password

我们得找到这个函数
image

image

image-20230209203211658

返回结果

image-20230209203230108

定制返回格式

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

# 使用规范
1 写个函数:jwt_response_payload_handler
def jwt_reponse_payload_hander(token,user=None,request=None):
  return {
    'code': 100,
    'msg': '登录成功',
    'token': user.username,
    'icon': user.icon
  }

2 配置一下,项目配置文件
JWT_AUTH = {
  'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.jwt_response_payload_handler'
}

3 使用postman测试,login登录username, password就能看到返回的格式

image-20230209222013671

jwt的认证类

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

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

image-20230209210616037

postman访问结果:

意思就是你带了token,带错了不行,没带反而可以

image-20230209211426386

这样就必须携带:请求头中key值叫Authorization,value值是: jwt 空格 有效的token值

image-20230209211542830

结果:

image-20230209212430860

posted @   小福福  阅读(81)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
  1. 1 原来你也在这儿 温余福
  2. 2 世间美好和你环环扣扣 温余福
  3. 3 随风起舞 温余福
  4. 4 罪恶都市 温余福
罪恶都市 - 温余福
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 王星

作曲 : 灰鸿啊/皮皮

编曲 : 夏日入侵企画

制作人 : 邢硕

节奏吉他 : 肯尼

主音吉他 : 张伟楠

贝斯 : 皮皮

鼓 : 海鑫

和声 : 邢硕

音效制作 : 邢硕

录音 : 邢硕/夏国兴

混音 : 于昊

特别鸣谢 : 张伟楠

这城市的车流和这地表的颤抖

像一颗石子落入地心之后泛起的温柔

暗涌

河水流过转角她的楼

被梦魇

轻声呓语唤醒身后的幼兽

失效感官焦灼只剩下

麻木愚钝无从感受

共同支撑全都瓦解

只是我们现在都

已忘记到底是

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去陈旧的还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

眼看这情节开始变旧

所有的城池已失守

最终无法占有

无眠辗转

伴着人间破碎的旧梦

像繁星

退却后只剩下混沌的夜空

炙热

掩盖风声鹤唳的担忧

把所有失落无助反手推入

无尽的白昼

失效感官焦灼只剩下

麻木愚钝无从感受

共同支撑全都瓦解

只是我们现在都已经忘记到底是

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

眼看这情节开始变旧

所有的城池早已失守

惶恐难以接受

缠绵往复不肯放手

最终无法占有

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁 灭 即 拯 救

谁掠夺春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

明知城池已失守

缠绵往复不肯放手

最终无法占有

点击右上角即可分享
微信分享提示