Django REST framework API 指南(14):權限

官方原文連接
本系列文章 github 地址
轉載請註明出處python

權限

與 authentication 和 throttling 一塊兒,permission 決定是應該接受仍是拒絕訪問請求。git

權限檢查老是在視圖的最開始處運行,在任何其餘代碼被容許進行以前。權限檢查一般會使用 request.userrequest.auth 屬性中的認證信息來肯定是否容許傳入請求。github

權限用於授予或拒毫不同類別的用戶訪問 API 的不一樣部分。django

最簡單的權限是容許經過身份驗證的用戶訪問,並拒絕未經身份驗證的用戶訪問。這對應於 REST framework 中的 IsAuthenticated 類。後端

稍微寬鬆的權限會容許經過身份驗證的用戶徹底訪問,而未經過身份驗證的用戶只能進行只讀訪問。這對應於 REST framework 中的 IsAuthenticatedOrReadOnly 類。api

如何肯定權限

REST framework 中的權限老是被定義爲權限類的列表。安全

在運行視圖的主體以前,檢查列表中的每一個權限。若是任何權限檢查失敗,則會引起 exceptions.PermissionDeniedexceptions.NotAuthenticated 異常,而且視圖的主體不會再運行。框架

當權限檢查失敗時,根據如下規則,將返回 「403 Forbidden」 或 「401 Unauthorized」 響應:ide

  • 該請求已成功經過身份驗證,但權限被拒絕。 — 將返回 403 Forbidden 響應。
  • 該請求未成功經過身份驗證,而且最高優先級身份驗證類未添加 WWW-Authenticate header。— 將返回 403 Forbidden 響應。
  • 該請求未成功經過身份驗證,不過最高優先級身份驗證類添加了 WWW-Authenticate header。— 返回一個 HTTP 401 Unauthorized 響應,並會帶上一個適當的 WWW-Authenticate header。

對象級權限

REST framework 權限還支持對象級權限。對象級權限用於肯定是否容許用戶對特定對象進行操做,該特定對象一般是指模型實例。函數

.get_object() 被調用時,對象級權限由 REST framework 的通用視圖執行。與視圖級權限同樣,若是用戶不被容許對給定對象進行操做,則會引起 exceptions.PermissionDenied 異常。

若是您正在編寫本身的視圖並但願強制執行對象級權限,或者若是您在通用視圖上重寫了 get_object 方法,那麼將須要顯式地在你檢索該對象時調用 .check_object_permissions(request, obj) 方法。

這將引起 PermissionDeniedNotAuthenticated 異常,或者只是在視圖具備適當的權限時才返回。

例如:

def get_object(self):
    obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
    self.check_object_permissions(self.request, obj)
    return obj
複製代碼

對象級權限的限制

出於性能緣由,通用視圖在返回對象列表時不會自動將對象級權限應用於查詢集中的每一個實例。

一般,當您使用對象級權限時,您還須要適當地過濾查詢集,以確保用戶只能看到他們被容許查看的實例。

設置權限策略

默認權限策略可使用 DEFAULT_PERMISSION_CLASSES setting 全局設置。例如。

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}
複製代碼

若是未指定,則此設置默認爲容許無限制訪問:

'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',
)
複製代碼

您還能夠在基於 APIView 類的視圖上設置身份驗證策略。

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)
複製代碼

或者在基於 @api_view 裝飾器的函數視圖上設置。

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
    content = {
        'status': 'request was permitted'
    }
    return Response(content)
複製代碼

注意: 當你經過類屬性或裝飾器設置新的權限類時,settings.py 文件中的默認設置會被忽略。


API 參考

AllowAny

AllowAny 權限類將容許不受限制的訪問,而無論該請求是否已經過身份驗證或未經身份驗證。

也不必定非要用此權限,能夠經過爲權限設置空列表或元組來實現相同的結果,可是你會發現,使用此權限使意圖更加清晰。

IsAuthenticated

IsAuthenticated 權限類將拒絕任何未經過身份驗證的用戶的訪問。

若是你但願 API 只能由註冊用戶訪問,則可使用此權限。

IsAdminUser

IsAdminUser 權限僅容許 user.is_staffTrue 用戶訪問,其餘任何用戶都將被拒絕。

若是你但願 API 只能被部分受信任的管理員訪問,則可使用此權限。

IsAuthenticatedOrReadOnly

IsAuthenticatedOrReadOnly 容許經過身份驗證的用戶執行任何請求。未經過身份驗證的用戶只能請求 「安全」 的方法: GETHEADOPTIONS

若是你但願 API 容許匿名用戶擁有讀取權限,而且只容許對已經過身份驗證的用戶執行寫入權限,則可使用此權限。

DjangoModelPermissions

此權限類與 Django 的標準 django.contrib.auth 模型權限綁定。此權限只能應用於具備 .queryset 屬性集的視圖。只有在用戶經過身份驗證並分配了相關模型權限的狀況下,纔有權限訪問。

  • POST 請求要求用戶在模型上具備 add 權限。
  • PUTPATCH 請求要求用戶在模型上具備 change 權限。
  • DELETE 請求要求用戶在模型上具備 delete 權限。

默認行爲也能夠被重寫以支持自定義模型權限。例如,你可能想要包含 GET 請求的 view 模型權限。

要自定義模型權限,請繼承 DjangoModelPermissions 並設置 .perms_map 屬性。有關詳細信息,請參閱源代碼。

使用不包含 queryset 屬性的視圖。

若是你將此權限與重寫 get_queryset() 方法的視圖一塊兒使用,則視圖上可能沒有 queryset 屬性。在這種狀況下,咱們建議使用 sentinel 查詢集標記視圖,以便此類能夠肯定所需的權限。例如:

queryset = User.objects.none()  # Required for DjangoModelPermissions
複製代碼

DjangoModelPermissionsOrAnonReadOnly

DjangoModelPermissions 相似,但也容許未經身份驗證的用戶對 API 進行只讀訪問。

DjangoObjectPermissions

該權限類與 Django 的標準對象權限框架綁定,該框架容許對每一個模型對象進行權限驗證。爲了使用此權限類,你還須要添加支持對象級權限的權限後端,例如 django-guardian

DjangoModelPermissions 同樣,此權限只能應用於具備 .queryset 屬性或 .get_queryset() 方法的視圖。只有在用戶經過身份驗證而且具備相關的每一個對象權限和相關的模型權限後,纔有權限訪問。

  • POST 請求要求用戶對模型實例具備 add 權限。
  • PUTPATCH 請求要求用戶對模型實例具備 change 權限。
  • DELETE 請求要求用戶對模型實例具備 delete 權限。

請注意,DjangoObjectPermissions 不須要 django-guardian 軟件包,而且一樣支持其餘對象級別的後端。

DjangoModelPermissions 同樣,你能夠經過繼承 DjangoObjectPermissions 並設置 .perms_map 屬性來自定義模型權限。有關詳細信息,請參閱源代碼。


注意: 若是你須要獲取 GETHEADOPTIONS 請求的對象級 view 權限,則還須要考慮添加 DjangoObjectPermissionsFilter 類,以確保列表端點只返回包含用戶具備查看權限的對象的結果。



自定義權限

要實現自定義權限,請繼承 BasePermission 並實現如下方法中的一個或兩個:

  • .has_permission(self, request, view)
  • .has_object_permission(self, request, view, obj)

若是請求被授予訪問權限,則方法應該返回 True,不然返回 False

若是你須要測試一個請求是一個讀操做仍是一個寫操做,你應該根據常量 SAFE_METHODS 檢查請求方法, SAFE_METHODS 是一個包含 'GET''OPTIONS''HEAD' 的元組。例如:

if request.method in permissions.SAFE_METHODS:
    # Check permissions for read-only request
else:
    # Check permissions for write request
複製代碼

Note: 只有在視圖級別 has_permission 檢查已經過時纔會調用實例級別的 has_object_permission 方法。還要注意,爲了運行實例級檢查,視圖代碼應該顯式調用 .check_object_permissions(request, obj)。若是你使用的是通用視圖,那麼默認狀況下會爲您處理。(基於函數的視圖將須要明確檢查對象權限,在失敗時引起 PermissionDenied。)


若是測試失敗,自定義權限將引起 PermissionDenied 異常。要更改與異常相關的錯誤消息,請直接在你的自定義權限上實現 message 屬性。不然將使用 PermissionDenieddefault_detail 屬性。

from rest_framework import permissions

class CustomerAccessPermission(permissions.BasePermission):
    message = 'Adding customers not allowed.'

    def has_permission(self, request, view):
         ...
複製代碼

舉個栗子

如下是一個權限類的示例,該權限類將傳入請求的 IP 地址與黑名單進行比對,並在 IP 被列入黑名單時拒絕該請求。

from rest_framework import permissions

class BlacklistPermission(permissions.BasePermission):
    """ Global permission check for blacklisted IPs. """

    def has_permission(self, request, view):
        ip_addr = request.META['REMOTE_ADDR']
        blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
        return not blacklisted
複製代碼

除了針對全部傳入請求運行的全局權限,還能夠建立對象級權限,這些權限僅針對影響特定對象實例的操做執行。例如:

class IsOwnerOrReadOnly(permissions.BasePermission):
    """ Object-level permission to only allow owners of an object to edit it. Assumes the model instance has an `owner` attribute. """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `owner`.
        return obj.owner == request.user
複製代碼

請注意,通用視圖將檢查適當的對象級權限,但若是你正在編寫本身的自定義視圖,則須要確保檢查本身的對象級權限。您能夠經過在擁有對象實例後從視圖中調用 self.check_object_permissions(request, obj) 來完成此操做。若是任何對象級權限檢查失敗,此調用將引起適當的 APIException,不然將簡單地返回。

另請注意,通用視圖將僅檢查單個模型實例的視圖的對象級權限。若是你須要列表視圖的對象級過濾,則須要單獨過濾查詢集。

相關文章
相關標籤/搜索