Ⅰ 接口文档
【一】接口文档了解
# 作为后端,接口写完了--->接口给前端使用
-登录接口:username,password ,code
# 写接口的人负责写接口文档
-如何写?
-写在哪?
# 通常在公司中:
1 使用world编写,放在公共平台上
2 使用MD编写
3 第三方平台编写:showdoc
-https://www.showdoc.com.cn/
4 自己开发:大公司
5 基于开源的 使用:YAPI 百度开源
-https://zhuanlan.zhihu.com/p/366025001
6 自动生成接口文档
# 自动生成接口文档步骤
-drf-->借助于第三方生成
-corapi
-drf-yasg
-drf-spectacular
-fastapi-->自带接口文档
# 接口文档规范(https://opendocs.alipay.com/open-v3/28d9fff7_alipay.trade.refund)
-接口解释
-地址
-请求方式
-请求参数:地址,头,体 参数说明,是否必填
-返回示例:字段解释
-错误码
- showdoc
【二】coreapi如何使用
# 【1】 安装:REST framewrok生成接口文档需要coreapi库的支持。
pip install coreapi
# 【2】 在路由中注册
'''
from rest_framework.documentation import include_docs_urls
urlpatterns = [
...
path('docs/', include_docs_urls(title='站点页面标题'))
]
'''
from rest_framework.documentation import include_docs_urls
urlpatterns = [
path('docs/', include_docs_urls(title='智慧社区项目')),
]
# 【3】 在视图类中写 视图类
-使用注释
--->写在类上的注释:单一方法的视图,可直接使用类视图的文档字符串
# 写登录接口
class UserViewSet(ViewSet):
'''
登录接口你值得拥有,给你想要的
'''
--->写在方法内的注释:包含多个方法的视图,在类视图的文档字符串中,分开方法定义
class BookListCreateView(generics.ListCreateAPIView):
"""
get:
返回所有图书信息.
post:
新建图书.
"""
对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
"""
list:
返回图书列表数据
retrieve:
返回图书详情数据
latest:
返回最新的图书数据
read:
修改图书的阅读量
"""
# 【4】 在序列化类中控制字段
-required # 非必填
-help_text # 字段描述
# extra_kwargs = {'price': {'required': False, 'help_text': '图书价格'}}
或者:
class Student(models.Model):
...
age = models.IntegerField(default=0, verbose_name='年龄', help_text='年龄')
...
# 【5】 配置文件配置
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}
# 【6】如果遇到报错
#AttributeError: 'AutoSchema' object has no attribute 'get_link'
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
# 新版drf schema_class默认用的是rest_framework.schemas.openapi.AutoSchema
}
# 【7】访问路径
http://localhost:8000/docs/
- 在视图类中写 视图类
- 在序列化类中控制字段
Ⅱ jwt介绍
【一】JWT认证
- 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token(本质就是token)认证机制。
- 作用是 不使用session机制,来存储记录用户登录信息
- jwt=Json Web Token:Json web token (JWT):常被用于认证,它是一个前端登录认证的方案,jwt就是token的一种
【二】token认证机制
# token认证机制
【1】 签发阶段:登录接口,登录成功,就签发
-token有 三部分,每部分用 . 分割 ,组装成一个字符串,每部分都用base64编码
头部:公司信息,加密方式等
荷载:真正数据部分,用户id,用户名字,过期时间,签发时间。。
签名:头部+荷载-->使用某种加密方式加密---》得到一个字符串
-直接返回给前端,不在后端存储
-前端拿到后,web:存到cookie中,小程序:存到小程序存储中 app:app存储中
【2】 认证阶段:需要登录后方的接口,要校验token是否合法
-前端携带 token在请求头中到后端,后端接收到后进行校验
-把头部和荷载使用同样的加密方式加密-->得到一个字符串 和第三部分比较是否一样
-如果一样,说明就是当前我们签发的,没有被别人篡改过-->校验通过
-取出用户id-->就能知道是哪个用户访问了
-如果不一样,说明就不是当前我们签发的,被别人篡改过-->校验不通过
【三】一个典型的token样式
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. # 头
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.# 荷载
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ # 签名
【1】header
wt的头部承载两部分信息:
- 声明类型,这里是jwt
- 声明加密的算法 通常直接使用 HMAC SHA256
完整的头部就像下面这样的JSON:
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
【2】payload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明 (建议但不强制使用) :
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避时序攻击。
公共的声明 : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
私有的声明 : 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
定义一个payload:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后将其进行base64加密,得到JWT的第二部分。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
【3】signature
WT的第三部分是一个签证信息,这个签证信息由三部分组成:
- 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
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
关于签发和核验JWT,我们可以使用Django REST framework JWT扩展来完成。
【4】本质原理
(1)jwt认证算法:签发与校验
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": "安全码"
}
(2)签发:根据登录请求提交来的 账号 + 密码 + 设备信息 签发 token
1)用基本信息存储json字典,采用base64算法加密得到 头字符串
2)用关键信息存储json字典,采用base64算法加密得到 体字符串
3)用头、体加密字符串再加安全码信息存储json字典,采用hash md5算法加密得到 签名字符串
账号密码就能根据User表得到user对象,形成的三段字符串用 . 拼接成token返回给前台
(3)校验:根据客户端带token的请求 反解出 user 对象
1)将token按 . 拆分为三段字符串,第一段 头加密字符串 一般不需要做任何处理
2)第二段 体加密字符串,要反解出用户主键,通过主键从User表中就能得到登录用户,过期时间和设备信息都是安全信息,确保token没过期,且时同一设备来的
3)再用 第一段 + 第二段 + 服务器安全码 不可逆md5加密,与第三段 签名字符串 进行碰撞校验,通过后才能代表第二段校验得到的user对象就是合法的登录用户
(4)drf项目的jwt认证开发流程(重点)
1)用账号密码访问登录接口,登录接口逻辑中调用 签发token 算法,得到token,返回给客户端,客户端自己存到cookies中
2)校验token的算法应该写在认证类中(在认证类中调用),全局配置给认证组件,所有视图类请求,都会进行认证校验,所以请求带了token,就会反解出user对象,在视图类中用request.user就能访问登录的用户
注:登录接口需要做 认证 + 权限 两个局部禁用
Ⅲ base64编码解码
# base64的长度一定是 4 的倍数,如果不足,要用 = 补齐, = 不表示数据,只是占位
# base64的作用
# jwt 使用base64编码
# 数据在互联网中传输,会使用base64编码后传输
# 图片的二进制-->转成base64在互联网中传输
import base64
import json
user_dict = {'name':'zyb','age':19,'user_id':741}
user_str = json.dumps(user_dict)
res = base64.b64encode(user_str.encode('utf-8'))
print(res) # eyJuYW1lIjogInp5YiIsICJhZ2UiOiAxOSwgInVzZXJfaWQiOiA3NDF9
res1=base64.b64decode('eyJuYW1lIjogInp5YiIsICJhZ2UiOiAxOSwgInVzZXJfaWQiOiA3NDF9') # 签名
print(res1)
# 头
res2=base64.b64decode('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9')
print(res2) # {"alg":"HS256","typ":"JWT"}
# 荷载
res3=base64.b64decode('eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9') # 签名
print(res3) # {"sub":"1234567890","name":"John Doe","admin":true}
# 签名
res3=base64.b64decode('TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ=') # 签名
print(res3) # L\x95@\xf7\x93\xab3\xb16p\x16\x9b\xdfDL\x1e\xb1\xc3pG\xf1\x8e\x86\x19\x81\xe1N4X{\x1e\x04
- 以12306的数码扫码登陆图片为例
s='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'
res=base64.b64decode(s)
print(res)
with open('a.jpg','wb') as f:
f.write(res)
标签:加密,解码,base64,jwt,接口,token,字符串
From: https://www.cnblogs.com/zyb123/p/18339625