赞
踩
DRF 限流原理:
匿名用户,使用ip地址标识访问者,存储每次访问的时间节点。
缓存: throttle_anon_ip<==> [时间戳1,时间戳2,…]
判断历史访问时间节点的长度 >= 限流次数,则拒绝;
每次请求过来时,查看self.history中是否有访问历史,若没有,则允许访问,并存储当前访问的时间节点self.history.inser(0, self.now);若有访问历史,先查看是否有过期的记录self.history[-1] <= self.now-self.duration,有则删除,然后判断访问次数是否超限len(self.history)。(及时循环删除过期的访问节点)
# 全局配置 # 全局配置 REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( # 限制所有匿名未认证用户,使用IP区分用户 'rest_framework.throttling.AnonRateThrottle', # 限制认证用户 'rest_framework.throttling.UserRateThrottle' ), # 配置限流频率 'DEFAULT_THROTTLE_RATES': { # 可以使用 second, minute, hour 或day来指明周期 # 匿名用户,每分钟3次请求 'anon': '3/minute', # 认证用户,每分钟5次请求 'user': '5/minute' } }
from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
page_size = 5 # 默认每页的条数
max_page_size = 6 # 最多每页条数
page_query_param = "page" # 页码的查询参数
page_size_query_param = "pagesize" # 查询参数中的每页显示的条数, 以此为准
# 用户信息视图
class UserInfoViewSet(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSer
pagination_class = MyPagination
2. 分页的重写
from django.core.paginator import InvalidPage # 重写 分页方法 class MyPagination(PageNumberPagination): """全局的分页,所有的list请求都会调用""" # 默认每页显示的条数,前端不传参数时,默认 page_size = 10 max_page_size = 20 # 每页最大显示的条数 #页码 参数 如 /users/?page=2&pagesize=3 page_query_param = "page" page_size_query_param = 'pagesize' # 前端发送的页数关键字名 # 可以重写分页的方法 def paginate_queryset(self, queryset, request, view=None): """ Paginate a queryset if required, either returning a page object, or `None` if pagination is not configured for this view. """ empty = True # 请求的分页 每页条数 page_size = self.get_page_size(request) if not page_size: # 没有要求分页,返回None return None paginator = self.django_paginator_class(queryset, page_size) # 获取页码 page_number = request.query_params.get(self.page_query_param, 1) # 最后一页 if page_number in self.last_page_strings: page_number = paginator.num_pages try: self.page = paginator.page(page_number) except InvalidPage as exc: empty = False if paginator.num_pages > 1 and self.template is not None: # The browsable API should display pagination controls. self.display_page_controls = True self.request = request if not empty: # 出异常 self.page = [] return list(self.page) def get_paginated_response(self, data): # 传入当前分页的数据 return Response(OrderedDict([ ('count', self.page.paginator.count if self.page else 0), ('next', self.get_next_link()), ('previous', self.get_previous_link()), ('code', 0), ('message', 'Ok'), ('results', data), ]))
from django.contrib.auth.models import AbstractUser from django.db import models # 用户模型类 class User(AbstractUser): mobile = models.CharField("手机号", max_length=11) user_type = models.ForeignKey(UserRole, on_delete=models.CASCADE, verbose_name="用户角色") # 角色模型类 class UserRole(models.Model): ROLES = ( (1, "普通会员"), (2, "黄金会员"), (3, "白金会员"), (4, "钻石会员") ) role = models.IntegerField("角色", choices=ROLES) # API 地址表 class Urls(models.Model): url = models.CharField("路由地址", max_length=200) visit_role = models.ManyToMany(Role)
from rest_framework.permissions import BasePermission from rest_framework.permissions import IsAuthenticated # 是否登录 from rest_framework.throttling import BaseThrottle # 访问频率 class MyPermission(BasePermission) def has_permission(self, request, view): # 权限校验通过 return True #否则 return False # 局部认证、鉴权、限流 class CheckView(APIView): pagination_class = MyPagination authentication_classes = [MyAuthentication,] permission_classes = (IsAuthenticated, MyPermission) throttle_classes = [] queryset = User.objects.all() serializer_class = UserSer
from rest_framework.permissions import BasePermission import re class MyPermission(BasePermission): def has_permission(self, request, view): # view为对应的要进入的视图 print("我的认证权限类:", view) # 权限认证,忽略登录的视图 if re.findall(r"login|admin", request.path_info, re.I): return True # 会话保持认证通过,会有request.user # 这里先查询用户 user = User.objects.filter(id=1).first() for i in user.role.all(): if i.name == "管理员": # 有权限访问 return True else: # 循环正常结束时,执行 return False
全局配置rest_framework的鉴权
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": ('users.utils.MyPermission'),
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。