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,不然将简单地返回。

另请注意,通用视图将仅检查单个模型实例的视图的对象级权限。若是你须要列表视图的对象级过滤,则须要单独过滤查询集。

相关文章
相关标签/搜索