Django drf 權(quán)限

2020-01-22 11:45 更新

權(quán)限

身份驗證或身份識別本身通常不足以獲取信息或代碼的訪問權(quán)限。因此,請求訪問的實體必須具有授權(quán)?!?nbsp;Apple Developer Documentation

連同認(rèn)證和限制,權(quán)限決定是否應(yīng)該接收請求或拒絕訪問。

權(quán)限檢查始終在視圖的開始處運行,在允許繼續(xù)執(zhí)行任何其他代碼之前運行。 權(quán)限檢查通常會使用request.user和request.auth屬性中的身份驗證信息來確定是否允許傳入請求。

權(quán)限用于授予或拒絕將不同類別的用戶訪問到API的不同部分。

最簡單的權(quán)限是允許訪問任何經(jīng)過身份驗證的用戶,并拒絕訪問任何未經(jīng)身份驗證的用戶。這對應(yīng)于REST框架中的IsAuthenticated類。

稍微嚴(yán)格的權(quán)限控制風(fēng)格是對經(jīng)過身份驗證的用戶的允許完全訪問,但對未經(jīng)身份驗證的用戶的允許只讀訪問。這對應(yīng)于REST框架中的IsAuthenticatedOrReadOnly類。

如何確定權(quán)限

REST框架中的權(quán)限始終被定義為一個權(quán)限類的列表。

在運行視圖的主體之前,檢查列表中的每個權(quán)限。 如果任何權(quán)限檢查失敗,會拋出一個exceptions.PermissionDenied或exceptions.NotAuthenticated異常,并且視圖的主體將不會運行。

當(dāng)權(quán)限檢查失敗時,將返回"403 Forbidden"或"401 Unauthorized"響應(yīng),具體根據(jù)以下規(guī)則:

  • 請求已成功通過身份驗證,但權(quán)限被拒絕。 — 將返回403 Forbidden響應(yīng)。
  • 請求未成功認(rèn)證,最高優(yōu)先級的認(rèn)證類不使用WWW-Authenticate標(biāo)頭。— 將返回403 Forbidden響應(yīng)。
  • 請求未成功認(rèn)證,最高優(yōu)先級的認(rèn)證類使用WWW-Authenticate標(biāo)頭。— 將返回HTTP 401未經(jīng)授權(quán)的響應(yīng),并附帶適當(dāng)?shù)腤WW-Authenticate標(biāo)頭。

對象級權(quán)限

REST框架權(quán)限還支持對象級的許可。對象級權(quán)限用于確定是否允許用戶操作特定對象(通常是模型實例)。

當(dāng)調(diào)用.get_object()時,由REST框架的通用視圖運行對象級權(quán)限檢測。 與視圖級別權(quán)限一樣,如果不允許用戶操作給定對象,則會拋出exceptions.PermissionDenied異常。

如果你正在編寫自己的視圖并希望強(qiáng)制執(zhí)行對象級權(quán)限檢測,或者你想在通用視圖中重寫get_object方法,那么你需要在檢索對象的時候顯式調(diào)用視圖上的.check_object_permissions(request, obj)方法。

這將拋出PermissionDenied或NotAuthenticated異常,或者如果視圖具有適當(dāng)?shù)臋?quán)限,則返回。

例如:

def get_object(self):
    obj = get_object_or_404(self.get_queryset())
    self.check_object_permissions(self.request, obj)
    return obj

對象級別的權(quán)限限制

出于性能原因,通用視圖在返回對象列表時不會自動將對象級權(quán)限應(yīng)用于查詢集中的每個實例。

通常,當(dāng)你使用對象級權(quán)限時,你還需要適當(dāng)?shù)剡^濾查詢集過濾查詢集,以確保用戶只能看到他們被允許查看的實例。

設(shè)置權(quán)限策略

默認(rèn)權(quán)限策略可以使用DEFAULT_PERMISSION_CLASSES設(shè)置進(jìn)行全局設(shè)置。比如:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

如果未指定,則此設(shè)置默認(rèn)為允許無限制訪問:

'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',
)

你還可以使用基于APIView類的視圖在每個視圖或每個視圖集的基礎(chǔ)上設(shè)置身份驗證策略。

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裝飾器裝飾基于函數(shù)的視圖。

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)

注意: 當(dāng)你通過類屬性或裝飾器設(shè)置新的權(quán)限類時,你要通知視圖忽略__settings.py__文件中設(shè)置的默認(rèn)列表。

API 參考

AllowAny

AllowAny權(quán)限類將允許不受限制的訪問,而不管該請求是否已通過身份驗證或未經(jīng)身份驗證。

此權(quán)限不是嚴(yán)格要求的,因為你可以通過使用空列表或元組進(jìn)行權(quán)限設(shè)置來獲得相同的結(jié)果,但你可能會發(fā)現(xiàn)指定此類很有用,因為它使意圖更明確。

IsAuthenticated

IsAuthenticated 權(quán)限類將拒絕任何未經(jīng)身份驗證的用戶的權(quán)限,并允許其他權(quán)限。 如果你希望你的API僅供注冊用戶訪問,則此權(quán)限適用。

如果你希望你的API允許匿名用戶讀取權(quán)限,并且只允許對已通過身份驗證的用戶進(jìn)行寫入權(quán)限,則此權(quán)限是適合的。

IsAdminUser

除非user.is_staff為True,否則IsAdminUser權(quán)限類將拒絕任何用戶的權(quán)限,在這種情況下將允許權(quán)限。

如果你希望你的API只能被部分受信任的管理員訪問,則此權(quán)限是適合的。

IsAuthenticatedOrReadOnly

IsAuthenticatedOrReadOnly 將允許經(jīng)過身份驗證的用戶執(zhí)行任何請求。只有當(dāng)請求方法是“安全”方法(GET, HEAD 或 OPTIONS)之一時,才允許未經(jīng)授權(quán)的用戶請求。

如果你希望你的API允許匿名用戶讀取權(quán)限,并且只允許對已通過身份驗證的用戶進(jìn)行寫入權(quán)限,則此權(quán)限是適合的。

DjangoModelPermissions

此權(quán)限類與Django的標(biāo)準(zhǔn)django.contrib.authmodel權(quán)限相關(guān)聯(lián)。此權(quán)限只能應(yīng)用于具有.queryset屬性集的視圖。只有在用戶通過身份驗證并分配了相關(guān)模型權(quán)限的情況下,才會被授予權(quán)限。

  • POST 請求要求用戶對模型具有添加權(quán)限。
  • PUT 和 PATCH 請求要求用戶對模型具有更改權(quán)限。
  • DELETE 請求想要求用戶對模型具有刪除權(quán)限。

默認(rèn)行為也可以被重寫以支持自定義模型權(quán)限。例如,你可能希望為GET請求包含一個查看模型的權(quán)限。

要使用自定義模型權(quán)限,請覆蓋DjangoModelPermissions并設(shè)置.perms_map屬性。有關(guān)詳細(xì)信息,請參閱源代碼。

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

如果你在重寫了get_queryset()方法的視圖中使用此權(quán)限,這個視圖上可能沒有queryset屬性。在這種情況下,我們建議還使用保護(hù)性的查詢集來標(biāo)記視圖,以便此類可以確定所需的權(quán)限。比如:

queryset = User.objects.none()  # DjangoModelPermissions需要一個queryset

DjangoModelPermissionsOrAnonReadOnly

與DjangoModelPermissions類似,但也允許未經(jīng)身份驗證的用戶具有對API的只讀訪問權(quán)限。

DjangoObjectPermissions

此權(quán)限類與Django的標(biāo)準(zhǔn)對象權(quán)限框架相關(guān)聯(lián),該框架允許模型上的每個對象的權(quán)限。為了使用此權(quán)限類,你還需要添加支持對象級權(quán)限的權(quán)限后端,例如django-guardian。

與DjangoModelPermissions一樣,此權(quán)限只能應(yīng)用于具有.queryset屬性或.get_queryset()方法的視圖。只有在用戶通過身份驗證并且具有相關(guān)的每個對象權(quán)限和相關(guān)的模型權(quán)限后,才會被授予權(quán)限。

  • POST 請求要求用戶對模型實例具有添加權(quán)限。
  • PUT 和PATCH 請求要求用戶對模型示例具有更改權(quán)限。
  • DELETE 請求要求用戶對模型示例具有刪除權(quán)限。

請注意,DjangoObjectPermissions 不需要 django-guardian軟件包,并且應(yīng)當(dāng)同樣支持其他對象級別的后端。

與DjangoModelPermissions一樣,你可以通過重寫DjangoObjectPermissions并設(shè)置.perms_map屬性來使用自定義模型權(quán)限。有關(guān)詳細(xì)信息,請參閱源代碼。

注意:如果你需要GET,HEAD和OPTIONS請求的對象級視圖權(quán)限,那么你還需要考慮添加DjangoObjectPermissionsFilter類,以確保相應(yīng)API只返回包含用戶具有適當(dāng)視圖權(quán)限的對象的結(jié)果。

自定義權(quán)限

要實現(xiàn)自定義權(quán)限,請重寫B(tài)asePermission并實現(xiàn)以下方法中的一個或兩個

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

如果請求被授予訪問權(quán)限,方法應(yīng)該返回True,否則返回False。

如果你需要測試請求是讀取操作還是寫入操作,則應(yīng)該根據(jù)常量SAFE_METHODS檢查請求方法,SAFE_METHODS是包含'GET', 'OPTIONS'和'HEAD'的元組。例如:

if request.method in permissions.SAFE_METHODS:
    # 檢查只讀請求的權(quán)限
else:
    # 檢查讀取請求的權(quán)限

注意: 僅當(dāng)視圖級has_permission檢查已通過時,才會調(diào)用實例級has_object_permission方法。另請注意,為了運行實例級別檢查,視圖代碼應(yīng)顯式調(diào)用.check_object_permissions(request, obj)。如果你使用的是通用視圖,那么默認(rèn)會為你處理。

如果校驗失敗,自定義權(quán)限將引發(fā)PermissionDenied異常。要更改與異常關(guān)聯(lián)的錯誤消息,請直接在自定義權(quán)限上實現(xiàn)消息屬性。否則將使用PermissionDenied的default_detail屬性。

from rest_framework import permissions

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

    def has_permission(self, request, view):
         ...

示例

以下是根據(jù)黑名單檢查傳入請求的IP地址的權(quán)限類的示例,如果IP已被列入黑名單,則拒絕該請求。

from rest_framework import permissions

class BlacklistPermission(permissions.BasePermission):
    """
    對列入黑名單的IP進(jìn)行全局權(quán)限檢查。
    """

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

除了針對所有傳入請求運行的全局權(quán)限外,還可以創(chuàng)建對象級權(quán)限,這些權(quán)限僅針對影響特定對象實例的操作運行。例如:

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    對象級權(quán)限僅允許對象的所有者對其進(jìn)行編輯
    假設(shè)模型實例具有`owner`屬性。
    """

    def has_object_permission(self, request, view, obj):
        # 任何請求都允許讀取權(quán)限,
        # 所以我們總是允許GET,HEAD或OPTIONS 請求.
        if request.method in permissions.SAFE_METHODS:
            return True

        # 示例必須要有一個名為`owner`的屬性
        return obj.owner == request.user

請注意,通用視圖將檢查適當(dāng)?shù)膶ο蠹墮?quán)限,但如果你正在編寫自己的自定義視圖,則需要確保檢查自己的對象級權(quán)限檢查。你可以通過在獲得對象實例后從視圖中調(diào)用self.check_object_permission(request,obj)來執(zhí)行此操作.如果任何對象級權(quán)限檢查失敗,此調(diào)用將引發(fā)適當(dāng)?shù)腁PIException,否則將簡單地返回。

另請注意,通用視圖僅檢查檢索單個模型實例的視圖的對象級權(quán)限。如果你需要列表視圖的對象級過濾,則需要單獨過濾查詢集。有關(guān)詳細(xì)信息,請參閱filtering文檔過濾文檔。

第三方包

以下第三方包都可以使用。

Composed Permissions

Composed Permissions提供了一種簡單的方法,使用小的可重用組件來定義復(fù)雜和多深度(使用邏輯運算符)權(quán)限對象。

REST Condition

REST Condition包是用于以簡單方便的方式構(gòu)建復(fù)雜權(quán)限的另一個擴(kuò)展。該擴(kuò)展允許你將權(quán)限與邏輯運算符組合在一起。

DRY Rest Permissions

DRY Rest Permissions包提供了為單個默認(rèn)和自定義操作定義不同權(quán)限的功能。此包適用于具有從應(yīng)用程序數(shù)據(jù)模型中定義的關(guān)系派生的權(quán)限的應(yīng)用程序。它還支持通過API的序列化程序返回到客戶端應(yīng)用程序的權(quán)限檢查。此外,它還支持向默認(rèn)和自定義列表操作添加權(quán)限,以限制他們?yōu)槊總€用戶檢索的數(shù)據(jù)。

Django Rest Framework Roles

Django Rest Framework Roles包使你可以更輕松地通過多種類型的用戶對API進(jìn)行參數(shù)化。

Django Rest Framework API Key

Django Rest Framework API Key包允許你確保向服務(wù)器發(fā)出的每個請求都需要一個API密鑰標(biāo)頭。您可以從django管理界面生成一個。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號