当前位置:   article > 正文

Django Rest framework Permissions_rest_framework.permissions

rest_framework.permissions

权限(Permissions)和认证(Authentication)以及节流(Throttling)一起决定一个请求是否会被接受或拒绝。
权限检查会在视图最开始执行,先于视图中的其他代码。权限校验通常使用认证阶段产生的request.userrequest.auth参数。
最简单的权限校验是接受所有携带了认证用户的请求以及用户未被认证的访问只读信息的请求。这中权限控制可以通过REST Framework的IsAuthenticatedOrReadOnly

权限的确定

Rest framework中的权限由permissions列表决定。
在运行视图主体之前,权限列表中的每一权限都会被检查。如果任一权限不满足,则会导致exceptions.PermissionDeniedexceptions.NotAuthenticated
当权限校验失败,则会导致’403 Forbidden’或’401 Unauthorized’相应,遵循以下规则:

  • 请求被成功认证,但权限校验失败,返回403
  • 请求成功认证,最优先认证类没有使用WWW-Authenticate请求头,返回403
  • 请求没有成功认证,最优先认证类使用WWW-Authenticated请求头,返回401并携带WWW-Authenticate响应头。
对象级别的权限

RF权限也支持对象级别的权限校验。对象级别的权限用于校验用户是否允许对特定的对象执行相关操作,对象通常是模型实例。
对象级别的权限在RF的通用视图的get_object()方法被调用时执行。与视图级别的权限相同,当用户没有操作给定对象的权限时,会导致exceptions.PermissionDenied异常。
如果你在自定义视图并希望执行对象级别的权限校验,或者你在一个通用视图中重写了get_object方法,那么你需要在检索特定对象时专门调用.check_object_permissions(request, obj)方法。
要么法奥之PermissionDeniedNoeAuthenticated异常,要么返回响应。
例:

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
  • 1
  • 2
  • 3
  • 4

注意 除了DjangoObjectPermissionsrest_framework.permissions并没有实现检查对象操作权限的方法。
如果你希望使用提供的权限类检查对象权限,你必须继承他们并实现Custom permission部分描述的has_object_permission()方法。

对象级别权限的限制

出于对性能的考虑,当响应返回对象列表时,通用视图并不会对queryset中的每一个实例作权限校验。
大部分情况下,当你使用对象级别的权限校验时,你需要设置适当的条件查询queryset,以保证用户见到的都是有操作权限的对象。

设置权限策略

默认的权限策略可以作为全局设置,在settings中设置DEFAULT_PREMISSION_CLASSES。例:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5

如果没有指定,这一设置默认为对请求作非严格校验:

'DEFAULT_PERMISSION_CLASSES': [
   'rest_framework.permissions.AllowAny',
]
  • 1
  • 2
  • 3

可以对每一个视图或视图集单独设置权限政策。使用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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

使用@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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

注意当对视图类或视图函数单独设置权限时,会忽略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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

注意权限组合支持 &(and),|(or),~(not)

接口参考

AllowAny

这是一种非严格的权限,对请求是否认证不做限制。引用这一权限和不引用权限是一致的,常用于在把某些视图排除校验。

IsAuthenticated

这一权限会拒绝所有非认证请求。

IsAdminUser

这一权限会让视图仅接受user.is_staff为True的请求。

IsAuthenticatedOrReadOnly

这一权限会让视图接受所有有认证用户的请求,或接受没有认证用户但请求方法为GETHEADOPTIONS的请求。

DjangoModelPermissions

这一权限与标准的django.contrib.auth模型权限绑定。只有设置了.queryset属性的视图才会执行此类权限校验。只有用户被认证且具有相关权限的请求才会被接受。

  • POST请求需要用户具有add权限
  • PUT/PATCH请求需要用户具有change权限
  • DELETE请求需要用户具有delete权限
没有queryset属性的视图使用此权限

如果视图中重写了get_queryset()方法,那么可能没有定义queryset属性。这种情况下,建议在视图中标记一个虚拟的query_set属性,这样可以执行需要的权限校验。比如:
queryset = User.objects.none() # Required for DjangoModelPermissions

DjangoModelPermissionsOrAnonReadOnly

在DjangoModelPermission的基础上允许未认证用户访问只读接口

DjangoObjectPermissions

这一权限与django标注的对象权限框架绑定,这些框架可以校验对象级别的权限,你需要添加支持对象级别权限的后台才能使用这一权限类,比如django-guardian
和DjangoModelPermissions一样,这一权限同样只适用于定义了.queryset属性或.get_queryset()方法的视图。只用用户被认证且具有指定对象的相关权限时请求才会被接受。
注意如果你希望GETHEAD以及OPTIONS请求也校验对象界别的权限且djangp-guardian作为对象级别权限的后台,那么可以考虑使用djangorestframework-guardianDjangoObjectPermissionsFilter类。他可以保证list接口返回的对象只包含用户有相应权限的对象。

自定义权限

继承BasePermission并调用以下方法即可使用自定义的权限:

  • .has_permission(self, request, view)
  • .has_object_permission(self, request, view, obj)
    这些方法在请求可以被接受时返回True否则返回False。
    如果要检查一个请求是读操作还是写操作,只要将请求方法与常量SAFE_METHODS对比即可,该常量是包含GETOPTIONS以及HEAD的元组。比如:
if request.method in permissions.SAFE_METHODS:
    # Check permissions for read-only request
else:
    # Check permissions for write request
  • 1
  • 2
  • 3
  • 4

注意 只有视图级别的has_permission校验通过才会调用实例级别的has_object_permission方法。视图必须调用.check_object_permissions(request, obj)才会执行实例级别的权限校验。如果你使用通用视图,那么已经默认调用了该方法。
如果校验失败,自定义的权限必须抛出PermissionDenied异常。通过定义message参数可以修改与异常关联的错误信息,否则会使用PermissionDenieddefault_detail属性。

from rest_framework import permissions

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

    def has_permission(self, request, view):
    ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

以下是一个检查请求的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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

和全局权限一样,这会对所有请求作校验,你也可以创建对象级别的权限,这种权限只有在操作影响特定对象实例时才会校验。比如:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

注意,通用视图会检查对象级别的权限,当如果你自定义视图,那么你需要自行检查对象级别的权限。你也可以通过调用视图中的self.check_object_permissions(request, obj)检查对对象的操作权限。如果校验失败,对该方法得调用会抛出APIException异常。
同时,通用视图只会对检索但个模型实例的视图校验对象级别的权限,如果你需要对列表视图作对象级别的筛选,那么你需要筛选和时查询集。见筛选文档

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/71658
推荐阅读
相关标签
  

闽ICP备14008679号