Django REST framework認證權限和限制和頻率

認證、權限和限制

身份驗證是將傳入請求與一組標識憑據(例如請求來自的用戶或其簽名的令牌)相關聯的機制。而後 權限 和 限制 組件決定是否拒絕這個請求。前端

簡單來講就是:json

認證肯定了你是誰後端

權限肯定你能不能訪問某個接口app

限制肯定你訪問某個接口的頻率dom

認證

REST framework 提供了一些開箱即用的身份驗證方案,而且還容許你實現自定義方案。ide

我的 敲碼log:函數

1.源碼分析

# Create your models here.
class UserInfo1(models.Model):
    id = models.AutoField(primary_key=True)  # 建立一個自增的主鍵字段
    # 建立一個varchar(64)的惟一的不爲空的字段
    name = models.CharField(null=False, max_length=20)
    pwd = models.CharField(max_length=32,default=123)

class Token(models.Model):
    user = models.OneToOneField("UserInfo1",on_delete=models.CASCADE)
    token = models.CharField(max_length=128)

2.post

# 我須要一個隨機字符串
def get_random_str(user):
    import hashlib, time
    ctime = str(time.time())
    # 封裝bytes類型一個MD5的加密對象
    md5 = hashlib.md5(bytes(user, encoding="utf8"))
    # md5.update 是拼接的效果,隨機生成md5值
    md5.update(bytes(ctime, encoding="utf8"))
    return md5.hexdigest()


# 認證、權限和限制
class LoginModelView(APIView):
    def post(self, request):
        name = request.data.get("name")
        pwd = request.data.get("pwd")

        user = models.UserInfo1.objects.filter(name=name, pwd=pwd).first()
        res = {"state_code": 1000, "msg": None}
        if user:
            # 返回了一個usermd5 加密的字符串
            random_str = get_random_str(user.name)
            """
            當存在token時,則更新,不存在則建立,defaults: 是由 (field, value) 對組成的字典,用於更新對象。 
            返回一個由 (object, created)組成的元組,
            object: 是一個建立的或者是被更新的對象,
            created: 是一個標示是否建立了新的對象的布爾值。                      
            """
            token = models.Token.objects.update_or_create(user=user, defaults={"token": random_str})
            res["token"] = random_str
        else:
            res["state_code"] = 1001  # 錯誤狀態碼
            res["msg"] = "用戶名或者密碼錯誤"

        import json
        # 這是由於json.dumps 序列化時對中文默認使用的ascii編碼.想輸出真正的中文須要指定ensure_ascii=False:
        # 若是你這樣的話就能把中文轉成json字符串,而不是 \u4e2d\u56fd
        return Response(json.dumps(res,ensure_ascii=False))

 

Django update_or_create 分析

update_or_create(defaults=None, **kwargs)
defaults 的值不一樣則建立,相同則更新

Member.objects.update_or_create(defaults={'user':1}, others={'field1':1,'field2':1})
當存在user=1時,則更新,不存在則建立編碼

update_or_create 用法:

update_or_create(defaults=None, **kwargs)

kwargs: 來更新對象或建立一個新的對象。

defaults: 是由 (field, value) 對組成的字典,用於更新對象。

 

返回一個由 (object, created)組成的元組,

object: 是一個建立的或者是被更新的對象,

created: 是一個標示是否建立了新的對象的布爾值。

 

update_or_create: 方法經過給出的kwarg

 

 

 

 

定義一個認證類(詳情請看 源碼分析)

好處:

1.他能判斷你是不是當前登陸用戶,當你沒有帶認證碼 向我後端發請求的時候我是不會給你數據的。

2.他每一次登陸的認證都會改變。

局部視圖認證

示例1:

class TokenAuth(object):
    def authenticate(self, request):
        # 取到 request裏面的 token值
        totken = request.GET.get("token")
        token_obj = models.Token.objects.filter(token=totken).first()
        if not token_obj:
            # 拋認證字段的異常
            raise exceptions.AuthenticationFailed("驗證失敗")
        else:
            return token_obj.user.name,token_obj.token

    def authenticate_header(self,request):
        pass
# 多條數據
class BookView(APIView):
    # 定義一個認證類
    authentication_classes = [TokenAuth]

 

而沒有定義 token類的依然能夠訪問。

 

 

 

全局級別認證

 

 

# 定義全局認證,全部視圖都須要認證
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES" : ["app01.utils.TokenAuth"]

}

 

 

from app01 import models
from rest_framework import exceptions


class TokenAuth(object):
    def authenticate(self, request):
        # 取到 request裏面的 token值
        totken = request.GET.get("token")
        token_obj = models.Token.objects.filter(token=totken).first()
        if not token_obj:
            # 拋認證字段的異常
            raise exceptions.AuthenticationFailed("驗證失敗")
        else:
            return token_obj.user.name, token_obj.token

    def authenticate_header(self, request):
        pass

 

權限

只有VIP用戶才能看的內容。

 

 

 

 

from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
    message="只有超級用戶才能訪問"
    def has_permission(self,request,view):
        username=request.user
        user_type=User.objects.filter(name=username).first().user_type

        if user_type==3:

            return True # 經過權限認證
        else:
            return False

 

# 封裝了3層
class AuthorDetaiView(viewsets.ModelViewSet):
    permission_classes = [SVIPpermission,]
    throttle_classes = [] # 限制某個ip 每分鐘訪問次數不能超過20次
    # authentication_classes = [TokenAuth]
    # queryset serializer 這兩個方法必定要定義成這個否則取不到值
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializers

限制(頻率組件)

# 自定義局部限制

 

 

 

 

import time

# 自定義限制
VISIT_RECORD = {}
class VisitRateThrottle(object):
    def __init__(self):
        self.history = None

    def allow_request(self, request, view):

        """
        自定義頻率限制60秒內只能訪問三次
        """
        # 獲取用戶IP
        ip = request.META.get("REMOTE_ADDR")
        # 獲取當前時間戳
        timestamp = time.time()

        # 若是當前訪問ip沒有在列表中 我就新建一個IP訪問記錄
        if ip not in VISIT_RECORD:
            VISIT_RECORD[ip] = [timestamp, ]
            # 能夠經過驗證
            return True

        # 若是列表中有值,我就取噹噹前ip地址 賦值給變量
        history = VISIT_RECORD[ip]
        self.history = history
        # 在列表頭部 插入一個時間戳
        history.insert(0, timestamp)
        # 若是列表有值,最早插入的值小於 當前值-60 ,tiemstamp是當前時間是在增長的
        while history and history[-1] < timestamp - 60:
            # pop 取出 最後一個條件成立的值
            history.pop()
        # 列表中的時間戳 大於3 就返回falsse,不然經過
        if len(history) > 3:
            return False
        else:
            return True

    def wait(self):
        # 返回給前端還剩多少時間能夠訪問
        timestamp = time.time()
        # 求出還剩多少時間能夠訪問
        return 60 - (timestamp - self.history[-1])
# 視圖使用
from
rest_framework.response import Response class AuthorModelView(viewsets.ModelViewSet): authentication_classes = [TokenAuth, ] permission_classes = [SVIPPermission, ] throttle_classes = [VisitRateThrottle, ] # 限制某個IP每分鐘訪問次數不能超過20次 queryset = Author.objects.all() serializer_class = AuthorModelSerializers # 分頁 # pagination_class = MyPageNumberPagination # renderer_classes = []

# 全局使用

# 在settings.py中設置rest framework相關配置項
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.TokenAuth", ],
    "DEFAULT_PERMISSION_CLASSES": ["app01.utils.SVIPPermission", ],
    "DEFAULT_THROTTLE_CLASSES": ["app01.utils.MyThrottle", ],
}

二:內置頻率類的使用

定義頻率類,必須繼承SimpleRateThrottle類:

複製代碼
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
# 必須配置scope參數 經過scope參數去settings中找頻率限定的規則 scope = 'throttle'
# 必須定義 get_cache_key函數 返回用戶標識的key 這裏借用源碼中BaseThrottle類(SimpleRateThrottle的父類)中的get_ident函數返回用戶ip地址 def get_cache_key(self, request, view): return self.get_ident(request)
複製代碼

局部使用:

視圖函數中加上
throttle_classes = [VisitThrottle,]

全局使用:settings中配置

REST_FRAMEWORK={
    'DEFAULT_THROTTLE_CLASSES':['utils.common.VisitThrottle'],
# 局部使用也要在settings中配置上 DEFAULT_THROTTLE_RATES 經過self.scope取頻率規則 (一分鐘訪問3次) 'DEFAULT_THROTTLE_RATES':{'throttle':'3/m',} }

設置錯誤信息爲中文:

複製代碼
class Course(APIView):
    authentication_classes = [TokenAuth, ]
    permission_classes = [UserPermission, ]
    throttle_classes = [MyThrottles,]

    def get(self, request):
        return HttpResponse('get')

    def post(self, request):
        return HttpResponse('post')
    # 函數名爲throttled 重寫Throttled類中默認的錯誤信息
    def throttled(self, request, wait):
        from rest_framework.exceptions import Throttled
        class MyThrottled(Throttled):
            default_detail = '訪問頻繁'
            extra_detail_singular = '等待 {wait} second.'
            extra_detail_plural = '等待 {wait} seconds.'
        raise MyThrottled(wait)
相關文章
相關標籤/搜索