1. 程式人生 > 實用技巧 >Django---drf,JWT補充、基於就角色的許可權控制(django內建auth體系)

Django---drf,JWT補充、基於就角色的許可權控制(django內建auth體系)

目錄

昨日回顧

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

作業:

必做

0 自定義jwt認證類

1 多方式登入,邏輯寫在檢視類中

2 多方式登入,邏輯寫在序列化類中

3 畫出django內建auth的六表邏輯

4 整理django快取的使用

選做

1 瞭解一下什麼是對稱加密,什麼是非對稱加密

2 Vue-cli建立vue專案,在pycharm中開啟