Django(63)drf許可權原始碼分析與自定義許可權

Silent丿丶黑羽發表於2021-06-14

前言

上一篇我們分析了認證的原始碼,一個請求認證通過以後,第二步就是檢視許可權了,drf預設是允許所有使用者訪問
 

許可權原始碼分析

原始碼入口:APIView.py檔案下的initial方法下的check_permissions

def check_permissions(self, request):
    """
    檢查是否應允許該請求。如果請求不被允許,則引發適當的異常。
    """
    for permission in self.get_permissions():
        if not permission.has_permission(request, self):
            self.permission_denied(
                request,
                message=getattr(permission, 'message', None),
                code=getattr(permission, 'code', None)
            )

許可權在get_permissions方法中獲取到,原始碼如下:

def get_permissions(self):
      """
      例項化並返回此檢視所需的許可權列表。
      """
      return [permission() for permission in self.permission_classes]

permission_classes又等於api_settings.DEFAULT_PERMISSION_CLASSES,所以我們去settings.py檔案中查詢

'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],

我們會發現drf預設的許可權是AllowAny,我們去看下原始碼:

class AllowAny(BasePermission):
    """
    允許任意訪問。這不是嚴格要求的,因為您可以使用空的 permission_classes 列表,但它很有用,因為它使意圖更加明確。
    """

    def has_permission(self, request, view):
        return True

我們可以看到AllowAny繼承自BasePermission,然後定義了has_permission方法,返回值為True

drf為我們提供了4個系統許可權認證:

1. AllowAny
認證規則全部返回True:`return True`
    遊客與登入使用者都有所有許可權

2. IsAuthenticated
認證規則必須有登入的合法使用者:`return bool(request.user and request.user.is_authenticated)`
    遊客沒有任何許可權,登入使用者才有許可權

3. IsAdminUser
認證規則必須是:`return bool(request.user and request.user.is_staff)`
    遊客沒有任何許可權,登入使用者才有許可權

4. IsAuthenticatedOrReadOnly
    認證規則必須是隻讀請求或者是合法使用者無限制
        return bool(
            request.method in SAFE_METHODS or
            request.user and
            request.user.is_authenticated
        )
        遊客只讀,合法使用者無限制

 

自定義認證類

  1. 建立繼承BasePermission的許可權類
  2. 實現has_permission方法
  3. 實現體根據許可權規則 確定 有無許可權
  4. 進行全域性或區域性配置(一般採用區域性配置)

許可權規則
滿足設定的使用者條件,代表有許可權,返回True
不滿足設定的使用者條件,代表有許可權,返回False

自定義許可權

from django.contrib.auth.models import Group
from rest_framework.permissions import BasePermission


class MyPermissions(BasePermission):
    def has_permission(self, request, view):
        rule1 = request.method in ['GET', 'OPTIONS', 'HEAD']
        group = Group.objects.filter(name="管理員").first()
        groups = request.user.groups.all()
        rule2 = group in groups
        rule3 = group and groups
        return rule1 or (rule2 and rule3)

以上定義了3條規則

  • rule1:請求方法是GETOPTIONSHEAD遊客和使用者都可以訪問
  • rule2:當前使用者如果有多個分組,其中必須有一個分組是管理員
  • rule3:管理員分組必須存在,使用者必須在分組中

接下里我們定義檢視

class TestView(APIView):
    permission_classes = [MyPermissions]

    def get(self, request, *args, **kwargs):
        print(request.user)
        return APIResponse(data_msg="所有使用者都可以訪問")

    def post(self, request, *args, **kwargs):
        print(request.user)
        return APIResponse(data_msg="只有管理員使用者可以訪問")

檢視中只是新增了permission_classes = [MyPermissions]屬與區域性配置,也就是自定義的許可權只針對此檢視,其他檢視還是預設的全域性配置,如果我們還有其他的關於許可權的需求,只需要在自定義的許可權類中寫邏輯即可

相關文章