JWT相关 , 自动生成接口文档,Django的缓存机制
Posted Hao-Mao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JWT相关 , 自动生成接口文档,Django的缓存机制相关的知识,希望对你有一定的参考价值。
自动生成接口文档
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:
修改图书的阅读量
"""
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),
1 jwt
1.1 控制用户登录后才能访问,和不登录就能访问
# 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\')
1.2 控制登录接口返回的数据格式
# 2 控制登录接口返回的数据格式
-第一种方案,自己写登录接口
-第二种写法,用内置,控制登录接口返回的数据格式
-jwt的配置信息中有这个属性
\'JWT_RESPONSE_PAYLOAD_HANDLER\':
\'rest_framework_jwt.utils.jwt_response_payload_handler\',
-重写jwt_response_payload_handler,配置成咱们自己的
1.3 自定义基于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(\'您没有携带认证信息\')
1.4 手动签发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(\'用户不存在\')
1.5 jwt的配置参数
# jwt的配置
import datetime
JWT_AUTH={
\'JWT_RESPONSE_PAYLOAD_HANDLER\':\'app02.utils.my_jwt_response_payload_handler\',
\'JWT_EXPIRATION_DELTA\': datetime.timedelta(days=7), # 过期时间,手动配置
}
2 基于角色的权限控制(django内置auth体系)
# RBAC :是基于角色的访问控制(Role-Based Access Control ),公司内部系统
# django的auth就是内置了一套基于RBAC的权限系统
# django中
# 后台的权限控制(公司内部系统,crm,erp,协同平台)
user表
permssion表
group表
user_groups表是user和group的中间表
group_permissions表是group和permssion中间表
user_user_permissions表是user和permission中间表
# 前台(主站),需要用三大认证
# 演示:
3 django缓存
# 前端混合开发缓存的使用
-缓存的位置,通过配置文件来操作(以文件为例)
-缓存的粒度:
-全站缓存
中间件
MIDDLEWARE = [
\'django.middleware.cache.UpdateCacheMiddleware\',
。。。。
\'django.middleware.cache.FetchFromCacheMiddleware\',
]
CACHE_MIDDLEWARE_SECONDS=10 # 全站缓存时间
-单页面缓存
在视图函数上加装饰器
from django.views.decorators.cache import cache_page
@cache_page(5) # 缓存5s钟
def test_cache(request):
import time
ctime=time.time()
return render(request,\'index.html\',context={\'ctime\':ctime})
-页面局部缓存
{% load cache %}
{% cache 5 \'name\' %} # 5表示5s钟,name是唯一key值
{{ ctime }}
{% endcache %}
# 前后端分离缓存的使用
- 如何使用
from django.core.cache import cache
cache.set(\'key\',value可以是任意数据类型)
cache.get(\'key\')
-应用场景:
-第一次查询所有图书,你通过多表联查序列化之后的数据,直接缓存起来
-后续,直接先去缓存查,如果有直接返回,没有,再去连表查,返回之前再缓存
以上是关于JWT相关 , 自动生成接口文档,Django的缓存机制的主要内容,如果未能解决你的问题,请参考以下文章