django-jwt | django快取
阿新 • • 發佈:2022-03-03
昨日回顧
# 1 自定義了頻率類 # 2 自動生成介面文件 # 3 jwt:三部分組成:頭+荷載(使用者資料)+簽名 # 4 drf中使用jwt:djangorestframework_jwt -路由裡配了一條 # 作業 1 自定義User表,新增mobile唯一約束欄位;新增icon圖片欄位 2 在自定義User表基礎上,用 GenericViewSet + CreateModelMixin + serializer 完成User表新增介面(就是註冊介面)(重要提示:序列化類要重寫create方法,不然密碼就是明文了) 3 在自定義User表基礎上,用 GenericViewSet + RetrieveModelMixin + serializer 完成User表單查(就是使用者中心) 4 在自定義User表基礎上,用 GenericViewSet + UpdateModelMixin + serializer 完成使用者頭像的修改
今日內容
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/[email protected]",
"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')
-應用場景:
-第一次查詢所有圖書,你通過多表聯查序列化之後的資料,直接快取起來
-後續,直接先去快取查,如果有直接返回,沒有,再去連表查,返回之前再快取
補充
1 補充base64使用
# base64編碼和解碼
#md5固定長度,不可反解
#base63 變長,可反解
#編碼(字串,json格式字串)
import base64
import json
dic={'name':'lqz','age':18,'sex':'男'}
dic_str=json.dumps(dic)
ret=base64.b64encode(dic_str.encode('utf-8'))
print(ret)
# 解碼
# ret是帶解碼的串
ret2=base64.b64decode(ret)
print(ret2)