Django Rest Framework 認證、權限-源碼分析及使用技巧

pip3 install djangorestframework

認證類

認證源碼梳理

  • 從rest_framework的dispatch開始入手觀察源碼

在dispatch中,對原生request進行了封裝

def dispatch(self, request, *args, **kwargs):
    self.args = args
    self.kwargs = kwargs
    # 對原生的request進行加工,包含【原生request】豐富了authenticator
    request = self.initialize_request(request, *args, **kwargs)
    # 獲取原生的request對象 request._request
    # 獲取認證類對象 request.authenticators
    self.request = request
    self.headers = self.default_response_headers  # deprecate?
    
    try:
        # 2. 認證
        self.initial(request, *args, **kwargs)
    .....
  • 認證

跟進self.initial

def initial(self, request, *args, **kwargs):
    self.format_kwarg = self.get_format_suffix(**kwargs)

    '''版本處理'''
    neg = self.perform_content_negotiation(request)
    request.accepted_renderer, request.accepted_media_type = neg
    ......

    '''進行認證'''
    self.perform_authentication(request)
    '''權限控制'''
    self.check_permissions(request)
    '''訪問頻率'''
    self.check_throttles(request)

然後繼續跟進,調用了.user._authenticate()方法 # 獲取認證對象進行一個一個認證,如果錯誤就觸發異常!

認證方法

這是認證和視圖寫在了一起,方便觀看,實際中最好將認證類單獨存放在一個py中

from rest_framework.views import APIView
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication  # 內置的認證類【必須繼承】

class Authentication(BaseAuthentication): # 自己寫認證,然後引用
    def authenticate(self, request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            # 其實在內部捕捉了異常
            raise exceptions.AuthenticationFailed('用戶認證失敗')

        # 返回user對象 + token
        # 在rest framework 內部會將兩個字段賦值給 request,給後面調用
        '''返回值必須是元祖 第一個賦值給 request.user  第二個request.auth'''
        return (token_obj.user, token_obj) 

    def authenticate_header(self, request):
        pass
        ...

class DogView(APIView):
    """
    應用上Authentication認證規則。如果有多個,那麼依次認證
    如果都沒有認證,那麼默認值 request.user=AnonymousUser  request.auth = None  匿名用戶
    request.user  這是token_obj.user 源碼中規定元祖第一個
    request.auth  這是token_obj  源碼中規定元祖第二個
    """
    authentication_classes = [Authentication, ]
    ......

源碼流程圖

image

setting中配置認證類

實際中將自己寫的認證方法單獨放在一個py中,然後在項目setting中配置即可

# 導入自己寫的rest 認證路徑
"""
可以局部使用或者全局使用    
局部: authentication_classes = [] 
"""
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ['app01.utils.auth.Authentication', ],  # 全局使用的認證類,也可以局部使用
    "UNAUTHENTICATED_USER": None,  # 匿名用戶, request.user = None
    "UNAUTHENTICATED_TOKEN": None,  # 匿名用戶, request.auth = None
}

這樣寫的好處是無需再視圖中再寫引用了,會自動按照你setting中的配置進行認證,如果指定視圖不需要認證,那麼在該view中寫 authentication_classes = [] 即可

內置的認證

  • BaseAuthentication 主要使用的就是這個
  • BasicAuthentication 瀏覽器內置的認證【大家瞭解下就是了】
  • 剩下的就是基於django的用戶認證了

權限類

源碼流程與認證相似

  1. 必須繼承 BasePermission 並實現has_permission 方法
  2. massage = ‘自定義無權限的提示’
  3. 返回值: True or False 有權無權訪問
  4. setting中加入配置

setting.py

REST_FRAMEWORK = {
    # 權限和用戶認證同理
    "DEFAULT_PERMISSION_CLASSES": ['app01.utils.permission.MyPermission', ],  # 全局權限控制,也可以局部使用
}

premission.py

from rest_framework.permissions import BasePermission  # 儘量必須繼承


class MyPermission(BasePermission):
    massage = '你沒有權限訪問'

    def has_permission(self, request, view):
        if request.user.user_type != 3:
            return False
        return True

使用總結

  1. 創建類: 繼承BaseAuthentication - 實現 authenticate方法

  2. 返回值 結果
    None 執行下一個認證
    raise 認證失敗拋出異常
    元祖(元素1,元素2) 元素1=request.user; 元素2=request.auth
  3. 全局使用

    setting中配置,然後在單獨的py文件中寫入認證「寫入路徑」

  4. 局部使用

    在視圖中 引入authentication_classes = [認證類, ]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章