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

前言

上一篇我們分析了認證的源碼,一個請求認證通過以後,第二步就是查看許可權了,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:請求方法是GET、OPTIONS、HEAD遊客和用戶都可以訪問
  • 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]屬與局部配置,也就是自定義的許可權只針對此視圖,其他視圖還是默認的全局配置,如果我們還有其他的關於許可權的需求,只需要在自定義的許可權類中寫邏輯即可

Tags: