官方原文連接
本系列文章 github 地址
轉載請註明出處python
與 authentication 和 throttling 一塊兒,permission 決定是應該接受仍是拒絕訪問請求。git
權限檢查老是在視圖的最開始處運行,在任何其餘代碼被容許進行以前。權限檢查一般會使用 request.user
和 request.auth
屬性中的認證信息來肯定是否容許傳入請求。github
權限用於授予或拒毫不同類別的用戶訪問 API 的不一樣部分。django
最簡單的權限是容許經過身份驗證的用戶訪問,並拒絕未經身份驗證的用戶訪問。這對應於 REST framework 中的 IsAuthenticated
類。後端
稍微寬鬆的權限會容許經過身份驗證的用戶徹底訪問,而未經過身份驗證的用戶只能進行只讀訪問。這對應於 REST framework 中的 IsAuthenticatedOrReadOnly
類。api
REST framework 中的權限老是被定義爲權限類的列表。安全
在運行視圖的主體以前,檢查列表中的每一個權限。若是任何權限檢查失敗,則會引起 exceptions.PermissionDenied
或 exceptions.NotAuthenticated
異常,而且視圖的主體不會再運行。框架
當權限檢查失敗時,根據如下規則,將返回 「403 Forbidden」 或 「401 Unauthorized」 響應:ide
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)
方法。
這將引起 PermissionDenied
或 NotAuthenticated
異常,或者只是在視圖具備適當的權限時才返回。
例如:
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
文件中的默認設置會被忽略。
AllowAny
權限類將容許不受限制的訪問,而無論該請求是否已經過身份驗證或未經身份驗證。
也不必定非要用此權限,能夠經過爲權限設置空列表或元組來實現相同的結果,可是你會發現,使用此權限使意圖更加清晰。
IsAuthenticated
權限類將拒絕任何未經過身份驗證的用戶的訪問。
若是你但願 API 只能由註冊用戶訪問,則可使用此權限。
IsAdminUser
權限僅容許 user.is_staff
爲 True
用戶訪問,其餘任何用戶都將被拒絕。
若是你但願 API 只能被部分受信任的管理員訪問,則可使用此權限。
IsAuthenticatedOrReadOnly
容許經過身份驗證的用戶執行任何請求。未經過身份驗證的用戶只能請求 「安全」 的方法: GET
, HEAD
或 OPTIONS
。
若是你但願 API 容許匿名用戶擁有讀取權限,而且只容許對已經過身份驗證的用戶執行寫入權限,則可使用此權限。
此權限類與 Django 的標準 django.contrib.auth
模型權限綁定。此權限只能應用於具備 .queryset
屬性集的視圖。只有在用戶經過身份驗證並分配了相關模型權限的狀況下,纔有權限訪問。
POST
請求要求用戶在模型上具備 add
權限。PUT
和 PATCH
請求要求用戶在模型上具備 change
權限。DELETE
請求要求用戶在模型上具備 delete
權限。默認行爲也能夠被重寫以支持自定義模型權限。例如,你可能想要包含 GET 請求的 view
模型權限。
要自定義模型權限,請繼承 DjangoModelPermissions
並設置 .perms_map
屬性。有關詳細信息,請參閱源代碼。
queryset
屬性的視圖。若是你將此權限與重寫 get_queryset()
方法的視圖一塊兒使用,則視圖上可能沒有 queryset
屬性。在這種狀況下,咱們建議使用 sentinel 查詢集標記視圖,以便此類能夠肯定所需的權限。例如:
queryset = User.objects.none() # Required for DjangoModelPermissions
複製代碼
與 DjangoModelPermissions
相似,但也容許未經身份驗證的用戶對 API 進行只讀訪問。
該權限類與 Django 的標準對象權限框架綁定,該框架容許對每一個模型對象進行權限驗證。爲了使用此權限類,你還須要添加支持對象級權限的權限後端,例如 django-guardian。
與 DjangoModelPermissions
同樣,此權限只能應用於具備 .queryset
屬性或 .get_queryset()
方法的視圖。只有在用戶經過身份驗證而且具備相關的每一個對象權限和相關的模型權限後,纔有權限訪問。
POST
請求要求用戶對模型實例具備 add
權限。PUT
和 PATCH
請求要求用戶對模型實例具備 change
權限。DELETE
請求要求用戶對模型實例具備 delete
權限。請注意,DjangoObjectPermissions
不須要 django-guardian
軟件包,而且一樣支持其餘對象級別的後端。
與 DjangoModelPermissions
同樣,你能夠經過繼承 DjangoObjectPermissions
並設置 .perms_map
屬性來自定義模型權限。有關詳細信息,請參閱源代碼。
注意: 若是你須要獲取 GET
,HEAD
和 OPTIONS
請求的對象級 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
屬性。不然將使用 PermissionDenied
的 default_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
,不然將簡單地返回。
另請注意,通用視圖將僅檢查單個模型實例的視圖的對象級權限。若是你須要列表視圖的對象級過濾,則須要單獨過濾查詢集。