1. 程式人生 > >Django REST framework基礎:認證、權限、限制

Django REST framework基礎:認證、權限、限制

bsp request history inf 機制 length pre div view

認證、權限和限制

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

簡單來說就是:

認證確定了你是誰

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

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

認證

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

技術分享圖片

接下類我們就自己動手實現一個基於Token的認證方案:

自定義Token認證

定義一個用戶表和一個保存用戶Token的表:

技術分享圖片
class UserInfo(models.Model):
    username 
= models.CharField(max_length=16) password = models.CharField(max_length=32) type = models.SmallIntegerField( choices=((1, 普通用戶), (2, VIP用戶)), default=1 ) class Token(models.Model): user = models.OneToOneField(to=UserInfo) token_code = models.CharField(max_length=128)
技術分享圖片

定義一個登錄視圖:

技術分享圖片
def get_random_token(username):
    """
    根據用戶名和時間戳生成隨機token
    :param username:
    :return:
    """
    import hashlib, time
    timestamp = str(time.time())
    m = hashlib.md5(bytes(username, encoding="utf8"))
    m.update(bytes(timestamp, encoding="utf8"))
    
return m.hexdigest() class LoginView(APIView): """ 校驗用戶名密碼是否正確從而生成token的視圖 """ def post(self, request): res = {"code": 0} print(request.data) username = request.data.get("username") password = request.data.get("password") user = models.UserInfo.objects.filter(username=username, password=password).first() if user: # 如果用戶名密碼正確 token = get_random_token(username) models.Token.objects.update_or_create(defaults={"token_code": token}, user=user) res["token"] = token else: res["code"] = 1 res["error"] = "用戶名或密碼錯誤" return Response(res)
技術分享圖片

定義一個認證類

技術分享圖片
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed


class MyAuth(BaseAuthentication):
    def authenticate(self, request):
        if request.method in ["POST", "PUT", "DELETE"]:
            request_token = request.data.get("token", None)
            if not request_token:
                raise AuthenticationFailed(缺少token)
            token_obj = models.Token.objects.filter(token_code=request_token).first()
            if not token_obj:
                raise AuthenticationFailed(無效的token)
            return token_obj.user.username, None
        else:
            return None, None
技術分享圖片

視圖級別認證

class CommentViewSet(ModelViewSet):

    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    authentication_classes = [MyAuth, ]

全局級別認證

# 在settings.py中配置
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ]
}

權限

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

自定義一個權限類

技術分享圖片
# 自定義權限
class MyPermission(BasePermission):
    message = VIP用戶才能訪問

    def has_permission(self, request, view):
        """
        自定義權限只有VIP用戶才能訪問
        """
        # 因為在進行權限判斷之前已經做了認證判斷,所以這裏可以直接拿到request.user
        if request.user and request.user.type == 2:  # 如果是VIP用戶
            return True
        else:
            return False
技術分享圖片

視圖級別配置

技術分享圖片
class CommentViewSet(ModelViewSet):

    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    authentication_classes = [MyAuth, ]
    permission_classes = [MyPermission, ]
技術分享圖片

全局級別設置

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

限制

DRF內置了基本的限制類,首先我們自己動手寫一個限制類,熟悉下限制組件的執行過程。

自定義限制類

技術分享圖片
VISIT_RECORD = {}
# 自定義限制
class MyThrottle(object):

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        """
        自定義頻率限制60秒內只能訪問三次
        """
        # 獲取用戶IP
        ip = request.META.get("REMOTE_ADDR")
        timestamp = time.time()
        if ip not in VISIT_RECORD:
            VISIT_RECORD[ip] = [timestamp, ]
            return True
        history = VISIT_RECORD[ip]
        self.history = history
        history.insert(0, timestamp)
        while history and history[-1] < timestamp - 60:
            history.pop()
        if len(history) > 3:
            return False
        else:
            return True

    def wait(self):
        """
        限制時間還剩多少
        """
        timestamp = time.time()
        return 60 - (timestamp - self.history[-1])
技術分享圖片

視圖使用

class CommentViewSet(ModelViewSet):

    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    throttle_classes = [MyThrottle, ]

全局使用

技術分享圖片
# 在settings.py中設置rest framework相關配置項
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
    "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
    "DEFAULT_THROTTLE_CLASSES": ["app01.utils.MyThrottle", ]
}
技術分享圖片

使用內置限制類

技術分享圖片
from rest_framework.throttling import SimpleRateThrottle


class VisitThrottle(SimpleRateThrottle):

    scope = "xxx"

    def get_cache_key(self, request, view):
        return self.get_ident(request)
技術分享圖片

全局配置

技術分享圖片
# 在settings.py中設置rest framework相關配置項
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
    # "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
    "DEFAULT_THROTTLE_CLASSES": ["app01.utils.VisitThrottle", ],
    "DEFAULT_THROTTLE_RATES": {
        "xxx": "5/m",
    }
}
技術分享圖片

Django REST framework基礎:認證、權限、限制