Django REST Framework API Guide 07

时间:2023-03-09 07:03:28
Django REST Framework API Guide 07

本节大纲

  1、Permissions

  2、Throttling

Permissions

权限是用来授权或者拒绝用户访问API的不同部分的不同的类的。基础的权限划分

1、IsAuthenticated
允许任何通过认证的用户访问,拒绝任何没有通过认证的用户。 2、IsAuthenticatedOrReadOnly
认证通过的用户有所有访问权限,反之只有只读权限

权限的定义

rest框架内的权限总是被定义成一个权限类的列表。主视图运行前检查,失败就引发exceptions.PermissionDenied或者exceptions.NotAuthenticated异常

权限检查失败会根据下面的情况返回'403 Forbidden'或'401 Unauthorized':

1、请求验证成功,权限拒绝  # 返回HTTP 403 Forbidden响应
2、请求没有验证成功,最上面的验证类没有使用'WWW-Authenticate'头 # 返回'HTTP 403 Forbidden' 响应
3、请求没有认证成功,最上面的认证类没有使用'WWW-Authenticate'头 # 返回'HTTP 401 Unauthorized'响应,带有一个合适的WWW-Authenticate头

对象级别的权限

在rest框架内,存在于一般视图的.get_object()方法里,如果不允许,引发exceptions.PermissionDenied异常。

如果您正在编写自己的视图,并且希望强制执行对象级别的权限,或者如果您在一般视图上重写.get_object()方法,那么您将需要在检索对象时显式地调用视图上的.check_object_per.(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

对象级别权限的限制

事实上,因为效率原因通用视图不会自动应用对象级别的权限到每一个实例里。通常,当使用对象级别权限时,还希望适当地过滤queryset,以确保用户只对它们允许查看的实例具有可见性。

设置权限策略

默认可以全局设置,使用DEFAULT_PERMISSION_CLASSES

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}

如果没有指定,默认设定是允许不受限制的访问

'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)

在CBV的View或者ViewSet上

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)

在FBV上

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)

API Reference

1、AllowAny

允许不受限制的访问,无论请求有没有被认证。

2、IsAuthenticated

拒绝没有通过认证的用户。适用于API只允许注册用户访问

3、IsAdminUser

拒绝任何的用户,除非user.is_staff为True才能访问

4、IsAuthenticatedOrReadOnly

允许通过认证的用户执行任何请求,没有通过认证的用户是只读权限,安全方法:GETHEAD 或者 OPTIONS.

DjangoModelPermissions

此权限绑定到Django标准的django.contrib.auth 模型权限。必须纸杯应用于有.queryset属性的视图。只有被认证并有相关模型权限的用户才能被授权

POST  # 对应model的add权限
PUT和PATCH # 对应model的change权限
delete # 对应model的delete权限

视图不包含queryset属性

如果view里面没有queryset,而是重写了get_queryset()方法,在这种案例里面,我们还建议用前哨查询设置标记视图,这样类能决定需要的权限。

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

DjangoModelPermissionOrAnonReadOnly

跟DjangoModelOermissions很像,没有认证的用户只读权限

DjangoObjectPermission

跟DjangoModelPermissions一样

Custom Permission

实施客制化权限,重写BasePermission,实行下面的方法中的一个或多个

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

这些方法在应该授权时返回True。你需要测试请求是读操作或写操作,应该检查请求方法是否在'GET', 'OPTIONS'和'HEAD' 组成的SAFE_METHODS里面

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。否则PermissionDenied的default_detail属性将被使用

from rest_framework import permissions

class CustomerAccessPermission(permissions.BasePermission):
message = 'Adding customers not allowed.' def has_permission(self, request, view):
...

示例

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

Throttling

节流(throttling)在rest框架内总是被定义成一组类的列表。同样在主题视图之前执行检查,失败引发exceptions.Throttled异常

设置节流策略

全局设置使用DEFAULT_THROTTLE_CLASSES和DEFAULT_THROTTLE_RATES参数。

REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}

DEFAULT_THROTTLE_RATES可以包含second, minute, hour或day作为节流周期。

你也可以为每个视图或者视图集设置节流,CBV格式

from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView class ExampleView(APIView):
throttle_classes = (UserRateThrottle,) def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)

在FBV里面

@api_view(['GET'])
@throttle_classes([UserRateThrottle])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)

设置缓存

节流类是REST框架提供的,使用了Django的缓存后端。你应该确保已经设置了合适的缓存设定。

如果你想使用一个缓存而不是默认的'default',你可以创建客制化的节流类并设置缓存cache属性

class CustomAnonRateThrottle(AnonRateThrottle):
cache = get_cache('alternate')

别忘了设置DEFAULT_THROTTLE_CLASSES或者使用throttle_classes视图属性

API Reference

AnonRateThrottle

AnonRateThrottle只限制没有认证的用户。访问请求的IP地址被用来生成唯一的键用来做限制。从下面几个方面来做请求率限制

1、类上的rate属性重写AnonRateThrottle并设置此属性
2、DEFAULT_THROTTLE_RATES['anon']设置

AnonRateThrottle很适合做对于未知资源请求的限制

UserRateThrottle

UserRateThrottle将通过一个给定的API速率来限制用户在API上的请求。用户的ID被用来生成唯一的节流键。未认证的请求将使用IP地址来生成唯一节流键。

请求的限定方面

1、rate属性,重写的UserRateThrottle,设置此属性
2、DEFAULT_THROTTLE_RATES['user']设置

一个API可能同时有多个UserRateThrottle在同一个地方。所以你需要重写UserRateThrottle并设置唯一'scope'为每一个类

class BurstRateThrottle(UserRateThrottle):
scope = 'burst' class SustainedRateThrottle(UserRateThrottle):
scope = 'sustained'
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'example.throttles.BurstRateThrottle',
'example.throttles.SustainedRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'burst': '60/min',
'sustained': '1000/day'
}
}

UserRateThrottle适用于如果想简单全局限制每位用户的速率。

ScopedRateThrottle

ScopedRateThrottle类被用来限制访问API的特殊部分。只有被访问的视图包含.throttle_scope属性时节流才被应用。然后,通过将请求的“scope”与唯一的用户ID或IP地址串联,形成唯一的节流键。被允许的请求速率被设置里面的DEFAULT_THROTTLE_RATES决定,通过使用键值scope

class ContactListView(APIView):
throttle_scope = 'contacts'
... class ContactDetailView(APIView):
throttle_scope = 'contacts'
... class UploadView(APIView):
throttle_scope = 'uploads'
...

然后设置全局

REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.ScopedRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'contacts': '1000/day', # 1000requests per day
'uploads': '20/day' # 20request per day
}
}

自定义 throttles

创建一个自定义节流,重写BaseThrottle执行.allow_request(self, request, view). 这个方法应该返回True如果请求应该被允许,否则False。同时你也需要重写.wait()方法,如果执行,.wait()方法讲返回一个推荐的的秒数在视图下一次请求之前。.wait()方法只有在.allow_request()返回false的时候将被调用

import random

class RandomRateThrottle(throttling.BaseThrottle):
def allow_request(self, request, view):
return random.randint(1, 10) != 1