Restful 4 -- 認證組件、權限組件、頻率組件、url註冊器、響應器、分頁器

1、認證組件、權限組件、頻率組件總結: 

  只有認證經過的用戶才能訪問指定的url地址,好比:查詢課程信息,須要登陸以後才能查看,沒有登陸,就不能查看,這時候須要用到認證組件python

一、認證組件格式

寫一個認證類
        from rest_framework.authentication import BaseAuthentication
        class MyAuth(BaseAuthentication):
            def authenticate(self,request):
        #         request  是封裝後的
                token = request.query_params.get('token')
                ret = models.UserToken.objects.filter(token=token).first()
                if ret:
        #             認證經過
                    return
                else:
                    raise AuthenticationFailed('認證失敗')
            #能夠不寫了
            def authenticate_header(self,ss):
                pass
局部使用
        authentication_classes=[MyAuth,MyAuth2]
全局使用
        查找順序:自定義的APIView裏找---》項目settings裏找---》內置默認的
        REST_FRAMEWORK={
            'DEFAULT_AUTHENTICATION_CLASSES':['utils.common.MyAuth',]

        }
View Code

二、權限組件格式

寫一個類
        class MyPermission():
            def has_permission(self,request,view):
                token=request.query_params.get('token')
                ret=models.UserToken.objects.filter(token=token).first()
                if ret.user.type==2:
                # 超級用戶能夠訪問
                    return True
                else:
                    return False
局部使用:
        permission_classes=[MyPermission,]
全局使用:
            REST_FRAMEWORK={
            'DEFAULT_PERMISSION_CLASSES':['utils.common.MyPermission',]
        }
View Code

三、頻率組建格式

寫一個類:
        from rest_framework.throttling import SimpleRateThrottle
        class VisitThrottle(SimpleRateThrottle):
            scope = 'xxx'
            def get_cache_key(self, request, view):
                return self.get_ident(request)
在setting裏配置:
            'DEFAULT_THROTTLE_RATES':{
                'xxx':'5/h',
            }
局部使用
        throttle_classes=[VisitThrottle,]
全局使用
        REST_FRAMEWORK={
            'DEFAULT_THROTTLE_CLASSES':['utils.common.MyPermission',]
        }
View Code

四、實例簡介:

  只有認證經過的用戶才能訪問指定的url地址,好比:查詢課程信息,須要登陸以後,沒有登陸,就不能查看,這時候須要認證組件數據庫

  結構目錄:

  1.mode層

class UserInfo(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    ss=((1,'超級用戶'),(2,'普通用戶'),(3,'二逼用戶'))
    type=models.IntegerField(choices=ss,null=True)

class UserToken(models.Model):
    user=models.OneToOneField(to='UserInfo')
    token=models.CharField(max_length=64)
View Code

  2.views層

from django.shortcuts import render,HttpResponse

# Create your views here.

import json
from rest_framework.views import APIView
from app01 import models
from utils.common import *
from rest_framework.response import Response

#登陸類
class Login(APIView):
    def post(self,request,*args,**kwargs):

        #實例化響應狀態函數(添加登陸成功後的狀態信息)
        response=MyResponse()

        #判斷用戶名、密碼是否正確
        name=request.data.get('name')
        pwd=request.data.get('pwd')
        user=models.UserInfo.objects.filter(name=name,pwd=pwd).first()

        #若是登陸成功生成一個隨機字符串
        if user:
            #生成一個隨機字符串
            token=get_token(name)
            #token表裏面的信息,若是不存在,會建立,若是存在會更新token值(由於進行了隨機時間加鹽),使用的是update_or_create
            ret=models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
            # ret=models.UserInfo.objects.update_or_create(id=1,defaults={'token':token}) 不是隻能寫user或者能夠寫id

            response.status=100
            response.msg='登陸成功'
            response.token=token
            print(response.get_dic())
        else:
            response.msg="用戶名密碼錯誤"
            # response.data='ddd'  最後response.get_dic(),均可以把這些信息返回

        #裏面須要傳入個字典
        return Response(response.get_dic())


#查看課程類
class Course(APIView):
    #局部登陸認證
    authentication_classes = [MyAuth,]
    #局部權限認證
    permission_classes = [Mypermission,]
    #局部頻率認證
    throttle_classes = [VisitThrottle,]
    def get(self,request):
        print(request.user)
        print(request.auth)
        return HttpResponse(json.dumps({'name':'python'}))
View Code

  3.url與settings

#url
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^course/', views.Course.as_view()),
    url(r'^login/', views.Login.as_view()),
]


#settings
#全局使用認證
REST_FRAMEWORK={
    #登陸認證,全局的登陸認證剛開始不要加,若是添加後初始登陸也會要求認證,那時數據庫尚未數據,會有問題(因此能夠在認證類裏面設置局部的認證並設置爲空)
    # 'DEFAULT_AUTHENTICATION_CLASSES':['utils.common.MyAuth',],
    #頻率
    'DEFAULT_THROTTLE_RATES':{
            # 'xxx':'5/m',
            'xxx':'5/hdddddddddddddddddddddddddddddd',
        }

} 


例如解決全局配置後login初始登陸會驗證的問題:
class Login(APIView):
    #爲了能夠在全局裏面統一設置,並不影響初始這裏的登陸
    authentication_classes=[]

    def post(self,request,*args,**kwargs):
    ...
    ...
View Code

  4.utils-common配置(組件類)

登陸狀態信息django

#帳戶登陸狀態信息
class MyResponse():
    def __init__(self):
        #1001表示失敗
        self.status = 1001
        self.msg = None

    def get_dic(self):
        #返回是字典格式的屬性信息
        return self.__dict__

隨機驗證碼:json

#傳入用戶名生成一個隨機驗證碼token
def get_token(name):
    md = hashlib.md5()
    md.update(name.encode('utf-8'))
    md.update(str(time.time()).encode('utf-8'))
    return md.hexdigest()
View Code

認證組件類:瀏覽器

from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework.exceptions import APIException,AuthenticationFailed
#認證組件
class MyAuth(BaseAuthentication):
    def authenticate(self, request):
        #拿到的是隨機token的值
        token = request.query_params.get('token')
        ret = models.UserToken.objects.filter(token=token).first()
        if ret:
            #認證經過
            return ret.user,ret
        else:
            #認證失敗
            raise AuthenticationFailed('認證失敗')
View Code

權限組件類:服務器

#權限組件
from rest_framework.permissions import BasePermission
class Mypermission(BasePermission):
    message = '不是超級用戶,查看不了'

    def has_permission(self, request, view):
        token = request.query_params.get('token')
        ret = models.UserToken.objects.filter(token=token).first()

        #拿到userinfo表格對應的type字段,輸出models裏面userinfo表格裏面type數字對應的「超級用戶」等字符串信息
        print(ret.user.get_type_display())
        if ret.user.type==1:
            return True

        #若是是Flase的狀況就會,打印上面的message信息
        else:
            return False
View Code

頻率組件類:app

#頻率組件
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
    scope = 'xxx'
    def get_cache_key(self, request, view):
        return self.get_ident(request)
View Code

運行效果展現:ide

準備工做:函數

1.userinfo數據表先添加2條數據,作演示post

狀況1:未登陸狀況下發送get請求,會提示認證失敗(由於沒有帶token信息)

狀況2:post請求登陸login,用戶信息寫入數據庫,同時生成將出入的name+time鹽,寫入UserToken表token字段

 狀況3:get請求攜帶token字符串,從而驗證權限認證、頻率認證

 

 

自定義頻率類:

自定義邏輯

1
2
3
4
5
#(1)取出訪問者ip
# (2)判斷當前ip不在訪問字典裏,添加進去,而且直接返回True,表示第一次訪問,在字典裏,繼續往下走
# (3)循環判斷當前ip的列表,有值,而且當前時間減去列表的最後一個時間大於60s,把這種數據pop掉,這樣列表中只有60s之內的訪問時間,
# (4)判斷,當列表小於3,說明一分鐘之內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利經過
# (5)當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗
class MyThrottles():
    VISIT_RECORD = {}
    def __init__(self):
        self.history=None
    def allow_request(self,request, view):
        #(1)取出訪問者ip
        # print(request.META)
        ip=request.META.get('REMOTE_ADDR')
        import time
        ctime=time.time()
        # (2)判斷當前ip不在訪問字典裏,添加進去,而且直接返回True,表示第一次訪問
        if ip not in self.VISIT_RECORD:
            self.VISIT_RECORD[ip]=[ctime,]
            return True
        self.history=self.VISIT_RECORD.get(ip)
        # (3)循環判斷當前ip的列表,有值,而且當前時間減去列表的最後一個時間大於60s,把這種數據pop掉,這樣列表中只有60s之內的訪問時間,
        while self.history and ctime-self.history[-1]>60:
            self.history.pop()
        # (4)判斷,當列表小於3,說明一分鐘之內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利經過
        # (5)當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗
        if len(self.history)<3:
            self.history.insert(0,ctime)
            return True
        else:
            return False
    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])
View Code

2、url註冊器、響應器、分頁器

一、url註冊器

  經過DRF的視圖組件,數據接口邏輯被咱們優化到最後剩下一個類,接下來,咱們使用DRF的url控制器來幫助咱們自動生成url,使用步驟以下:

from django.urls import re_path, include

# 1.導入模塊
from rest_framework import routers

from serializer import views
# 2.實例化一個router對象
router = routers.DefaultRouter()

# 3.將須要自動生成url的接口註冊到router中
router.register('books', views.BookView)

# 4.生成url
urlpatterns = [
    re_path('^', include(router.urls))
]

二、響應器

  以前咱們使用DRF的Response類來將數據響應給客戶端,不論是POSTMAN仍是瀏覽器,都能瀏覽到通過格式化後的漂亮的數據,DRF是怎麼作的呢?其實就是經過響應器組件。

  若是咱們不須要使用DRF提供給瀏覽器的格式化後的數據,只須要禁止該響應方式便可:

from rest_framework.renderers import JSONRenderer

class BookView(ModelViewSet):
    
    renderer_classes = [JSONRenderer]
    
    queryset = Book.objects.all()
    serializer_class = BookSerializer

  這樣,瀏覽器再次訪問,接收到的就是普通的json格式數據,而不是通過DRF格式化後的數據,renderer_classes的查找邏輯與以前的解析器等組件是徹底同樣的。

三、分頁器

  爲了服務器性能考慮,也爲了用戶體驗,咱們不該該一次將全部的數據從數據庫中查詢出來,返回給客戶端瀏覽器,若是數據量很是大,這對於服務器來說,能夠說是性能災難,而對於用戶來說,加載速度將會很是慢。

  因此,咱們須要控制每次返回給客戶端多少數據,這就須要用到分頁器。

一、接下來,介紹一下DRF的局部實現分頁器組件

# 1.導入模塊
from rest_framework.pagination import PageNumberPagination

# 自定義分頁器類,繼承PageNumberPagination
class MyPagination(PageNumberPagination):
    page_size = 3
    page_query_param = 'p'
    page_size_query_param = 'size'
    max_page_size = 5


class BookView(APIView):

    def get(self, request):
        # 2.獲取數據
        queryset = Book.objects.all()
        # 3.建立分頁器對象
        paginater = MyPagination()
        # 4.開始分頁
        paged_books = paginater.paginate_queryset(queryset, request)
        # 5.將分頁後的數據進行序列化
        serializer_books = BookSerializer(paged_books, many=True)
        # 6.返回數據
        return Response(serializer_books.data)
View Code

二、參數介紹

page_size:用來控制每頁顯示多少條數據(全局參數名爲PAGE_SIZE);
page_query_param:用來提供直接訪問某頁的數據;
page_size_query_param:臨時調整當前顯示多少條數據;
max_page_size:控制page_size_query_param參數能調整的最大條數;

三、在ModelViewSet中使用分頁器

from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination

# 自定義分頁器類
class MyPagination(PageNumberPagination):
    page_size = 3
    page_query_param = 'p'
    page_size_query_param = 'size'
    max_page_size = 5


class BookView(ModelViewSet):
    
    pagination_class = MyPagination      # 指定分頁器類

    queryset = Book.objects.all()
    serializer_class = BookSerializer
View Code

四、分頁器全局配置

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10  # 每頁數目
}
相關文章
相關標籤/搜索