首页 > 代码库 > API Guide(十四)之Permissions

API Guide(十四)之Permissions

权限

身份验证或身份识别本身通常不足以获取信息或代码的访问权限。为此,请求访问的实体必须具有授权。

- 苹果开发者文档

连同认证和限制,权限决定是否应该授予请求或拒绝访问。

在允许继续执行任何其他代码之前,权限检查始终在视图的开始处运行。权限检查通常将使用在所述认证信息request.userrequest.auth属性,以确定是否输入请求应该被允许。

权限用于授予或拒绝将不同类别的用户访问到API的不同部分。

最简单的权限是允许访问任何经过身份验证的用户,并拒绝访问任何未经身份验证的用户。这对应IsAuthenticated于REST框架中的类。

稍微严格的权限风格将是允许对经过身份验证的用户的完全访问,但允许对未经身份验证的用户的只读访问。这对应IsAuthenticatedOrReadOnly于REST框架中的类。

如何确定权限

REST框架中的权限始终被定义为许可类列表。

在运行主视图之前,检查列表中的每个权限。如果任何权限检查失败exceptions.PermissionDeniedexceptions.NotAuthenticated异常将被提升,视图的主体将不会运行。

当权限检查失败时,将返回“403禁止”或“401未授权”响应,根据以下规则:

  • 请求已成功通过身份验证,但权限被拒绝。 - 将返回HTTP 403 Forbidden响应。
  • 请求未成功认证,最高优先级的认证类使用WWW-Authenticate标头。 - 将返回HTTP 403 Forbidden响应。
  • 请求未成功认证,最高优先级的认证类确实使用WWW-Authenticate标头。- 返回HTTP 401未经授权的响应,并附带适当的WWW-Authenticate标题。

对象级权限

REST框架权限还支持对象级的许可。对象级权限用于确定是否允许用户对特定对象(通常是模型实例)采取行动。

调用对象级权限由REST框架的通用视图运行.get_object()。与视图级别权限一样,exceptions.PermissionDenied如果用户不允许对给定对象采取行动,则会引发异常。

如果您正在编写自己的视图并希望强制执行对象级权限,或者如果get_object在通用视图中覆盖该方法,那么您需要在检索到的位置显式调用.check_object_permissions(request, obj)视图上的方法目的。

这将引发PermissionDeniedNotAuthenticated异常,或者如果视图具有适当的权限,则返回。

例如:

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

对象级权限的限制

出于性能原因,当返回对象列表时,通用视图将不会自动将对象级别的权限应用于查询集中的每个实例。

通常当您使用对象级权限时,您还需要适当地过滤查询集,以确保用户只能在允许查看的实例上查看。

设置权限策略

使用该DEFAULT_PERMISSION_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.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模型拥有权限。
  • PUT并且PATCH请求要求用户对change模型具有许可。
  • DELETE请求要求用户对delete模型拥有权限。

也可以覆盖默认行为以支持自定义模型权限。例如,您可能需要viewGET请求添加模型权限。

要使用自定义模型权限,请覆盖DjangoModelPermissions并设置.perms_map属性。有关详细信息,请参阅源代码。

使用不包含queryset属性的视图。

如果您使用此权限使用覆盖get_queryset()方法queryset的视图,则视图上可能没有属性。在这种情况下,我们建议使用哨兵查询器标记视图,以便此类可以确定所需的权限。例如:

queryset = User.objects.none()  # Required for DjangoModelPermissions

DjangoModelPermissionsOrAnonReadOnly

类似于DjangoModelPermissions,但也允许未经身份验证的用户对API具有只读访问权限。

DjangoObjectPermissions

该权限类与Django的标准对象许可框架相关联,允许对模型进行每个对象的权限。为了使用此权限类,您还需要添加支持对象级权限的权限后端,例如django-guardian。

DjangoModelPermissions此相反,此权限只能应用于具有.queryset属性或.get_queryset()方法的视图。仅当用户进行身份验证并具有分配相关的每个对象权限相关模型权限时,授权才被授予。

  • POST请求要求用户拥有add模型实例的权限。
  • PUT并且PATCH请求要求用户对change模型实例拥有权限。
  • DELETE请求要求用户拥有delete模型实例的权限。

请注意,DjangoObjectPermissions 要求django-guardian包,并且应该支持其他对象级后端同样出色。

与之一样,DjangoModelPermissions您可以通过覆盖DjangoObjectPermissions和设置.perms_map属性来使用自定义模型权限。有关详细信息,请参阅源代码。


注意:如果你需要的对象级别view的权限GETHEADOPTIONS请求,你要还考虑增加的DjangoObjectPermissionsFilter类,以确保该列表只端点返回结果包括用户拥有适当的查看权限的对象。



自定义权限

要实现自定义权限,请覆盖BasePermission并实现以下方法之一或两者:

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

True如果请求被授予访问权限,则返回方法,否则返回False

如果您需要测试如果请求是读操作或写操作,你应该检查对常量的请求方法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_object_permission仅当视图级has_permission检查已经通过时,才会调用实例级方法。还要注意,为了运行实例级检查,视图代码应该显式调用.check_object_permissions(request, obj)。如果您使用通用视图,那么默认情况下会为您处理。


PermissionDenied如果测试失败,自定义权限将引发异常。要更改与异常关联的错误消息,message请直接在自定义权限上实现属性。否则将使用default_detail属性PermissionDenied

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如果任何对象级权限检查失败,此调用将提出适当的,否则将简单地返回。

另请注意,通用视图将仅检查检索单个模型实例的视图的对象级权限。如果需要对列表视图进行对象级过滤,则需要单独过滤查询集。有关详细信息,请参阅过滤文档。


第三方包

以下第三方软件包也可用。

组合权限

的组成权限包提供了一种简单的方式来定义复杂和多深度(与逻辑运算符)权限对象,使用小的和可重复使用的部件。

REST条件

在静止状态下包装的另一个扩展简单和方便的方式构建复杂的权限。该扩展允许您将权限与逻辑运算符组合。

干休息权限

该DRY休息权限包提供定义单个默认和自定义操作不同的权限的能力。此软件包适用于具有应用程序数据模型中定义关系的权限的应用程序。它还支持通过API的串行器返回给客户端应用程序的权限检查。此外,它还支持向默认和自定义列表操作添加权限,以限制每个用户检索的数据。

Django Rest框架角色

在Django的REST框架角色包使得它更容易在多个类型的用户参数的API。

Django Rest Framework API密钥

在Django的REST框架API密钥包,您可以确保服务器的每个请求需要一个API密钥头。您可以从django管理界面生成一个。

API Guide(十四)之Permissions