赞
踩
权限(Permissions)和认证(Authentication)以及节流(Throttling)一起决定一个请求是否会被接受或拒绝。
权限检查会在视图最开始执行,先于视图中的其他代码。权限校验通常使用认证阶段产生的request.user
和request.auth
参数。
最简单的权限校验是接受所有携带了认证用户的请求以及用户未被认证的访问只读信息的请求。这中权限控制可以通过REST Framework的IsAuthenticatedOrReadOnly
Rest framework中的权限由permissions列表决定。
在运行视图主体之前,权限列表中的每一权限都会被检查。如果任一权限不满足,则会导致exceptions.PermissionDenied
或exceptions.NotAuthenticated
。
当权限校验失败,则会导致’403 Forbidden’或’401 Unauthorized’相应,遵循以下规则:
WWW-Authenticate
请求头,返回403WWW-Authenticated
请求头,返回401并携带WWW-Authenticate
响应头。RF权限也支持对象级别的权限校验。对象级别的权限用于校验用户是否允许对特定的对象执行相关操作,对象通常是模型实例。
对象级别的权限在RF的通用视图的get_object()
方法被调用时执行。与视图级别的权限相同,当用户没有操作给定对象的权限时,会导致exceptions.PermissionDenied
异常。
如果你在自定义视图并希望执行对象级别的权限校验,或者你在一个通用视图中重写了get_object
方法,那么你需要在检索特定对象时专门调用.check_object_permissions(request, obj)
方法。
要么法奥之PermissionDenied
或NoeAuthenticated
异常,要么返回响应。
例:
def get_object(self):
obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
self.check_object_permissions(self.reques, obj)
return obj
注意 除了DjangoObjectPermissions
,rest_framework.permissions
并没有实现检查对象操作权限的方法。
如果你希望使用提供的权限类检查对象权限,你必须继承他们并实现Custom permission部分描述的has_object_permission()
方法。
出于对性能的考虑,当响应返回对象列表时,通用视图并不会对queryset中的每一个实例作权限校验。
大部分情况下,当你使用对象级别的权限校验时,你需要设置适当的条件查询queryset,以保证用户见到的都是有操作权限的对象。
默认的权限策略可以作为全局设置,在settings中设置DEFAULT_PREMISSION_CLASSES
。例:
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中的全局默认权限。
如果权限继承自rest_framework.permissions.BasePermission
,权限可以用Python位运算方式组合起来。比如IsAuthenticatedOrReadOnly
可以这样定义:
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS from rest_framework.response import Response from rest_framework.views import APIView class ReadOnly(BasePermission): def has_permission(self, request, view): return request.method in SAFE_METHODS class ExampleView(APIView): permission_classes = [IsAuthenticated|ReadOnly] def get(self, request, format=None): content = { 'status': 'request was permitted' } return Response(content)
注意权限组合支持 &(and),|(or),~(not)
这是一种非严格的权限,对请求是否认证不做限制。引用这一权限和不引用权限是一致的,常用于在把某些视图排除校验。
这一权限会拒绝所有非认证请求。
这一权限会让视图仅接受user.is_staff
为True的请求。
这一权限会让视图接受所有有认证用户的请求,或接受没有认证用户但请求方法为GET
、HEAD
或OPTIONS
的请求。
这一权限与标准的django.contrib.auth
模型权限绑定。只有设置了.queryset
属性的视图才会执行此类权限校验。只有用户被认证且具有相关权限的请求才会被接受。
add
权限change
权限delete
权限queryset
属性的视图使用此权限如果视图中重写了get_queryset()
方法,那么可能没有定义queryset
属性。这种情况下,建议在视图中标记一个虚拟的query_set属性,这样可以执行需要的权限校验。比如:
queryset = User.objects.none() # Required for DjangoModelPermissions
在DjangoModelPermission的基础上允许未认证用户访问只读接口
这一权限与django标注的对象权限框架绑定,这些框架可以校验对象级别的权限,你需要添加支持对象级别权限的后台才能使用这一权限类,比如django-guardian。
和DjangoModelPermissions一样,这一权限同样只适用于定义了.queryset
属性或.get_queryset()
方法的视图。只用用户被认证且具有指定对象的相关权限时请求才会被接受。
注意如果你希望GET
、HEAD
以及OPTIONS
请求也校验对象界别的权限且djangp-guardian作为对象级别权限的后台,那么可以考虑使用djangorestframework-guardian
的DjangoObjectPermissionsFilter
类。他可以保证list接口返回的对象只包含用户有相应权限的对象。
继承BasePermission
并调用以下方法即可使用自定义的权限:
.has_permission(self, request, view)
.has_object_permission(self, request, view, obj)
SAFE_METHODS
对比即可,该常量是包含GET
、OPTIONS
以及HEAD
的元组。比如:if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
注意 只有视图级别的has_permission
校验通过才会调用实例级别的has_object_permission
方法。视图必须调用.check_object_permissions(request, obj)
才会执行实例级别的权限校验。如果你使用通用视图,那么已经默认调用了该方法。
如果校验失败,自定义的权限必须抛出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地址是否在黑名单中的权限类:
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
异常。
同时,通用视图只会对检索但个模型实例的视图校验对象级别的权限,如果你需要对列表视图作对象级别的筛选,那么你需要筛选和时查询集。见筛选文档。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。