目录
Django REST framework 权限和限制
(你能干什么)
与身份验证和限制一起,权限确定是应该授予还是拒绝访问请求。
在允许任何其他代码继续之前,权限检查始终在视图的最开始运行。权限检查通常使用 request.user
和 request.auth
属性中的身份验证信息来确定是否应允许传入请求。
权限用于授予或拒绝不同类别的用户访问API的不同部分。
最简单的权限类型是允许访问任何经过身份验证的用户,并拒绝访问任何未经身份验证的用户。这对应IsAuthenticated
于REST框架中的类。
稍微不那么严格的权限样式是允许对经过身份验证的用户进行完全访问,但允许对未经身份验证的用户进行只读访问。这对应IsAuthenticatedOrReadOnly
于REST框架中的类。
设置权限的方法
可以使用该
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 APIViewclass 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文件中的默认列表集。
如果它们继承自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)
案例
此案例基于 Django REST framework 认证
第一步: 定义一个权限类
"""
自己动手写一个权限组件
"""
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
- message = '只有VIP才能访问'
-
- def has_permission(self, request, view):
- # 认证类中返回了token_obj.user, request_token
- # request.auth 等价于request_token
- if not request.auth:
- return False
- # request.user为当前用户对象
- if request.user and request.user.type == 1: # 如果是VIP用户
- print("requ", request.user, type(request.user))
- return True
- else:
- return False
'运行
第二步: 使用
视图级别
- class CommentViewSet(ModelViewSet):
-
- queryset = models.Comment.objects.all()
- serializer_class = app01_serializers.CommentSerializer
- authentication_classes = [MyAuth, ]
- permission_classes = [MyPermission, ]
全局级别设置
- # 在settings.py中设置rest framework相关配置项
- REST_FRAMEWORK = {
- "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
- "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
- }
---
限制
(你一分钟能干多少次?)**好像有点污~~ ###
第一步: 自定义限制类
- import time
-
- # from rest_framework.throttling import
- visit_record = {}
-
-
- class MyThrottle(object):
-
- def __init__(self):
- self.history = None
-
- def allow_request(self, request, view):
- # 拿到当前的请求的ip作为访问记录的 key
- ip = request.META.get('REMOTE_ADDR')
- # 拿到当前请求的时间戳
- now = time.time()
- if ip not in visit_record:
- visit_record[ip] = []
- # 把当前请求的访问记录拿出来保存到一个变量中
- history = visit_record[ip]
- self.history = history
- # 循环访问历史,把超过10秒钟的请求时间去掉
- while history and now - history[-1] > 10:
- history.pop()
- # 此时 history中只保存了最近10秒钟的访问记录
- if len(history) >= 3:
- return False
- else:
- # 判断之前有没有访问记录(第一次来)
- self.history.insert(0, now)
- return True
-
- def wait(self):
- """告诉客户端还需等待多久"""
- now = time.time()
- return self.history[-1] + 10 - now
-
-
- # history = ['9:56:12', '9:56:10', '9:56:09', '9:56:08'] # '9:56:18' - '9:56:12'
-
- # history = ['9:56:19', '9:56:18', '9:56:17', '9:56:08']
-
- # 最后一项到期的时间就是下一次允许请求的时间
-
- # 最后一项到期的时间:now - history[-1] > 10
-
- # 最后一项还剩多少时间过期
- # history[-1] + 10 - now
第二步: 使用
视图中使用
- class CommentViewSet(ModelViewSet):
-
- queryset = models.Comment.objects.all()
- serializer_class = app01_serializers.CommentSerializer
- throttle_classes = [MyThrottle, ]
全局中使用
- # 在settings.py中设置rest framework相关配置项
- REST_FRAMEWORK = {
- "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
- "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
- "DEFAULT_THROTTLE_CLASSES": ["app01.utils.MyThrottle", ]
- }
嫌麻烦的话,还可以使用内置限制类,哈哈~
- from rest_framework.throttling import SimpleRateThrottle
-
-
- class VisitThrottle(SimpleRateThrottle):
-
- scope = "xxx"
-
- def get_cache_key(self, request, view):
- return self.get_ident(request)
全局配置
- # 在settings.py中设置rest framework相关配置项
- REST_FRAMEWORK = {
- "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
- # "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
- "DEFAULT_THROTTLE_CLASSES": ["app01.utils.VisitThrottle", ],
- "DEFAULT_THROTTLE_RATES": {
- "xxx": "5/m",
- }
- }