认证类

认证类的作用:

实现某些接口,登录之后能访问,有的接口不登录就能访问

前期准备

登录接口:

首先写一个登录接口,这个接口返回token,下一次请求浏览器只要带着token过来,就是说明用户登录了,不带token,就说明没有登录。

所以这个token可以放在请求的什么位置?

请求首行 or 请求头 or 请求体

  • 对于post请求 ---> token可以放请求体
  • 对于get 请求 ---> get请求没有请求体,token可以放在请求首行的地址栏
  • 其实, 一般token放在请求头上传到后端。

前端传入的数据从哪里取?

  • 对于post请求中携带的token:

    原生django: request.body request.POST

    Django drf: request.data
  • 对于get请求中携带的token:

    原生django: request.get

    Django drf: request.query_params

综上所述,在这个我们的示例下token暂时通过get请求的地址栏(请求首行)传到后端。

通过实现一个需求,来学习认证组件:

  1. # 查询所有图书,不需要登录就能访问
  2. # 查询单个图书,需要登录才能访问

由于两个接口,一个登录才能访问,一个不登录也能访问,所以最好把两个接口分开两个类写。

通过simpleRouter生成路由,并实现对方法的映射。

自定义认证类

我们可以在视图类中添加authentications_classes类属性来实现对整个视图类的认证校验。

只要是继承了GenericAPIView的视图类中都有如下属性:

authentications_classes = [认证类,]

这个认证类需要我们自己写。

在app目录下,新键一个authenticate.py文件来存放我们自己写的认证类。

自己写的认证类,需要继承drf的认证基类BaseAuthentication

这个基类,有个authenticate方法必须得重写否则会抛出异常:

通过query_params方法获取get请求问号后面携带的token参数。根据请求中是否携带token,判断是否登录。

需要注意的是,当登录成功,要求固定返回两个值:

  • return (请求对应的用户,token)

当前用户没有登录则抛出AuthenticationFailed异常。

这个异常从如下位置导入:

from rest_framework.exceptions import AuthenticationFailed

至此我们已经把自定义认证类写好了,接下来需要在我们的视图进行配置。

配置认证类

将我们写好的认证类添加到authentications_classes类属性。

请注意,可以给一个视图添加多个认证类,他会从左到右执行。

这个视图类所有的方法,都需要经过认证类认证,才能执行。

我们通过认证类实现了上述需求。

全局配置

在django settings中配置可以实现全局生效(所有CBV)。

注意:

不要在django配置文件中乱导入不使用的东西,否则会报错:

这是因为先加载配置文件,再加载django项目。而app01是在django项目里面的,还没有成功加载,就导入,所以会报错。

局部禁用

也就是在authentication_classes类属性写一个空列表, 这表示该CBV局部禁用认证。

认证组件使用步骤

  1. # 1 写一个认证类,继承BaseAuthentication
  2. # 2 重写authenticate方法,在该方法在中实现登录认证:token在哪带的?如果认证它是登录了
  3. # 3 如果认证成功,返回两个值【返回None或两个值】
  4. # 4 认证不通过,抛异常AuthenticationFailed
  5. # 5 局部使用和全局使用
  6. -局部:只在某个视图类中使用【当前视图类管理的所有接口】
  7. class BookDetailView(ViewSetMixin, RetrieveAPIView):
  8. authentication_classes = [LoginAuth]
  9. -全局:全局所有接口都生效(登录接口不要)
  10. REST_FRAMEWORK = {
  11. 'DEFAULT_AUTHENTICATION_CLASSES':['app01.authenticate.LoginAuth']
  12. }
  13. -局部禁用:
  14. class BookDetailView(ViewSetMixin, RetrieveAPIView):
  15. authentication_classes = []
  16. '''
  17. 重写和重载
  18. 重写:方法名和参数一样。
  19. 重载:方法名一样,参数不一样。
  20. '''

认证类编写难点:

  • token在请求的哪里携带?
  • 如何获取用户上传的token?
  • 如何认证用户登录了?

基于类中方法的认证(了解)

认证类是通过类属性配置的,所以一个认证类会对于整个视图类生效。但有时候我们会有如下的需求:

一个CBV类中,某些方法,进行认证,其他方法,不走认证。

要实现这个需求有如下方式:

  • 方式一: 把我们写好的认证类添加到action装饰器的authentication_classes参数中.

  • 方式二: 使用原生django提供的装饰器

    如果想给视图类中的方法添加装饰器, 并且这个装饰器是我们手写的函数装饰器时,这个装饰器不能直接给类中的方法添加.

    而是需要使用django提供的一个装饰器来添加.

    没错,通过装饰器来添加装饰器!

    导入from django.utils.decorators import method_decorator

但是正常来说,应该把需要认证的接口和不需要认证的接口拆分开。(登录和未登录)

代码:

  1. ### 视图
  2. # 查询所有
  3. class BookView(ViewSetMixin, ListAPIView):
  4. queryset = Book.objects.all()
  5. serializer_class = BookSerializer
  6. # 查询单个
  7. class BookDetailView(ViewSetMixin, RetrieveAPIView):
  8. queryset = Book.objects.all()
  9. serializer_class = BookSerializer
  10. # authentication_classes = [LoginAuth] # 需要写一个认证类,需要咱们写
  11. ### 认证类代码
  12. class LoginAuth(BaseAuthentication):
  13. def authenticate(self, request):
  14. # 在这里实现认证,如果是登录的,继续往后走返回两个值,如果不是抛异常
  15. # 请求中是否携带token,判断是否登录,放在地址栏中
  16. token = request.query_params.get('token', None)
  17. if token: # 前端传入token了,去表中查,如果能查到,登录了,返回两个值[固定的:当前登录用户,token]
  18. user_token = UserToken.objects.filter(token=token).first()
  19. if user_token:
  20. return user_token.user, token
  21. else:
  22. # 没有登录抛异常
  23. raise AuthenticationFailed('token认证失败')
  24. else:
  25. raise AuthenticationFailed('token没传')
  26. ### 路由代码
  27. router.register('books', views.BookView, 'books')
  28. router.register('books', views.BookDetailView, 'books')

权限类

是否有这种情况,你登录小视频网站,但是有些视频即使登录了,也无法观看,只有VIP才能观看。

这就是因为你没有权限,从上述例子也可以看出,权限是认证的后一层校验。

对于程序员来说,需要给接口设置权限:

  1. # 即便登录成功了,有些接口,还是不能访问,因为没有权限
  2. # 登录后,有的接口有权限访问,有的没有权限访问

通过一个需求,来学习权限类:

  1. # 查询单个和查询所有接口,都要登录才能访问----》全局认证
  2. -查询单个需要超级管理员才能访问
  3. -查询所有,所有登录用户都能访问

前期准备

权限是一个字段,需要在user表中加入user_type字段。

通过user_type字段表示不同身份的用户。

备注: 如果模型字段使用了choice参数,就可以使用get_user_type_display方法拿到字段对应的中文。

重写has_permission()

和认证类套路相似,写一个权限类:

这个权限类继承权限基类,需要重写基类的has_permission()方法,在这个方法中实现权限认证。

需要注意的是这个方法的返回值:

  • 如果有权限,return True
  • 如果没有权限,return False

查看源码:

首先需要获取当前的用户,才能去数据库里查询该用户的user_type字段:

通过request.user可以拿到当前的用户,这个request.user属性是经过认证之后添加到request对象中的.

也就是认证函数authenticate的第一个返回值:

认证方法的返回值第一个是当前用户,会放在request.user。在权限类中可以使用request.user将其拿出来。

判断权限:

通过类属性配置权限:

注意,权限和认证都可以配置多个。

添加权限不足信息

控制权限给前端的提示信息:

权限相关说明:

  • 登录接口需要禁用权限,查询所有接口也需要禁用权限。
  • 权限并不是这么简单,权限类的逻辑可以很复杂。用表保存用户的权限,当请求来了去权限表获取单个用户的权限.

权限组件使用步骤

  1. # 1 写一个权限类,继承BasePermission
  2. # 2 重写has_permission方法,在该方法在中实现权限认证,在这方法中,request.user就是当前登录用户
  3. # 3 如果有权限,返回True
  4. # 4 没有权限,返回False,定制返回的中文: self.message='中文'
  5. # 5 局部使用和全局使用
  6. -局部:只在某个视图类中使用【当前视图类管理的所有接口】
  7. class BookDetailView(ViewSetMixin, RetrieveAPIView):
  8. permission_classes = [CommonPermission]
  9. -全局:全局所有接口都生效
  10. REST_FRAMEWORK = {
  11. 'DEFAULT_PERMISSION_CLASSES': [
  12. 'app01.permissions.CommonPermission',
  13. ],
  14. }
  15. -局部禁用:
  16. class BookDetailView(ViewSetMixin, RetrieveAPIView):
  17. permission_classes = []

频率类

频率类控制某个接口访问的频率(次数)。

频率类常用于反爬,因为爬虫的请求次数太快,导致服务器压力很大, 服务器崩溃。

通过一个需求,来学习频率类:

查询所有的接口,同一个ip一分钟只能访问5次。

(可以通过IP地址控制、也可以用户控制访问频率)

频率类还是熟悉的套路。

这里继承simpleRateThrottle:

重写get_cache_key()

需要重写get_cache_key()方法:

两种频率限制方法

这个方法返回什么,就以什么做频率限制:

(可以返回ip 或 用户ID)

如何获取客户端的ip地址?

使用reuquest.META,

在request.META是一个字典, 这里面存放着请求头的各种数据。

  • 以ip地址做限制:

  • 以用户id做限制:

  • 以电脑做限制,需要配合前端,将电脑的唯一标识传入后端。

配置固定的类属性scope

如果需要在视图类中配置频率需要做两件事:

  1. 频率类设置一个固定的类属性scope:

  2. 还需要配置django settings:



    可以发现类属性的值,和这里的键有对应关系。

    • 5/m:表示一分钟访问五次
    • 5/h:表示一小时访问五次

    他是会把字符串取第一个字符来判断是小时还是分钟。

    所以也可以这样写:5/maya ---> 一分钟五次

局部使用在类中设置频率类:

服务重启会重新计算这个时间。

全局配置频率类:

跟上面不同, 需要进行两项配置:

局部禁用频率类:

频率组件使用步骤

  1. # 1 写一个频率类,继承SimpleRateThrottle
  2. # 2 重写get_cache_key方法,返回什么,就以什么做限制----》ip,用户id做限制
  3. # 3 配置一个类属性:scope = 'book_5_m'
  4. # 4 在配置文件中配置
  5. 'DEFAULT_THROTTLE_RATES': {
  6. 'book_5_m': '5/m',
  7. },
  8. # 5 局部使用和全局使用
  9. -局部:只在某个视图类中使用【当前视图类管理的所有接口】
  10. class BookDetailView(ViewSetMixin, RetrieveAPIView):
  11. throttle_classes = [CommonThrottle]
  12. -全局:全局所有接口都生效
  13. REST_FRAMEWORK = {
  14. 'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],
  15. }
  16. -局部禁用:
  17. class BookDetailView(ViewSetMixin, RetrieveAPIView):
  18. throttle_classes = []

过滤类

restful规范中,要求了请求地址中带过滤条件。

  • 5个接口中,只有一个接口需要有过滤和排序,也就是查询所有接口.
  • 频率\认证\权限校验是多个接口都需要的.

需求:

  1. 查询 所有图书接口,查询以 开头的所有图书

内置过滤类 SearchFilter

  1. class BookView(ViewSetMixin, ListAPIView):
  2. queryset = Book.objects.all()
  3. serializer_class = BookSerializer
  4. # SearchFilter内置的,固定用法,模糊匹配
  5. # 就有过滤功能了,指定按哪个字段过滤
  6. filter_backends = [SearchFilter]
  7. # search_fields = ['name'] # 可以按名字模糊匹配
  8. search_fields = ['name','price'] # 可以按名字模糊匹配或价格模糊匹配
  9. # 可以使用的搜索方式
  10. http://127.0.0.1:8000/api/v1/books/?search=红 # name或price中只要有红就会搜出来
  11. # 继承APIView如何写,完全自己写,麻烦,但是清晰

配置过滤类的方式:

必须继承GenericAPIView,如果是APIView需要自己写过滤相关逻辑.

在视图类中配置:

需要指定按照哪些字段进行过滤。

通过search_field类属性,指定按照哪些字段过滤:

这个search_fields是固定的写法,同时前端必须用search提交查询参数。

可以按照多个字段,按照名字或价格字段模糊匹配:

示例:

只要名字或价格带939的, 都可以搜出来。

继承APIView怎么实现过滤?

全部都要自己写。

但是我们可以使用GenericAPIView自定义过滤类。

第三方过滤类 django-filter

  1. # 安装:django-filter
  2. class BookView(ViewSetMixin, ListAPIView):
  3. queryset = Book.objects.all()
  4. serializer_class = BookSerializer
  5. permission_classes = []
  6. authentication_classes = []
  7. throttle_classes = []
  8. filter_backends = [DjangoFilterBackend]
  9. filterset_fields = ['name','price'] # 支持完整匹配 name=聊斋11&price=933
  10. # 支持的查询方式
  11. http://127.0.0.1:8000/api/v1/books/?price=939
  12. http://127.0.0.1:8000/api/v1/books/?price=939&name=红楼猛

安装:

pip3.8 install django-filter -i https://pypi.tuna.tsinghua.edu.cn/simple

使用注意:

使用了第三方过滤类,就不使用search_fields类属性,而是使用filterset_fields类属性:

前端示例:

支持精确匹配。模糊匹配就是只要含有就可以匹配。

自定义过滤类

  1. # 查询价格大于100的所有图书
  2. http://127.0.0.1:8000/api/v1/books/?price_gt=100
  3. #第一步; 定义一个过滤类,继承BaseFilterBackend,重写filter_queryset方法
  4. class CommonFilter(BaseFilterBackend):
  5. def filter_queryset(self, request, queryset, view):
  6. # 在里面实现过滤,返回qs对象,就是过滤后的数据
  7. price_gt = request.query_params.get('price_gt', None)
  8. if price_gt:
  9. qs = queryset.filter(price__gt=int(price_gt))
  10. return qs
  11. else:
  12. return queryset
  13. # 第二步:配置在视图类上
  14. class BookView(ViewSetMixin, ListAPIView):
  15. queryset = Book.objects.all()
  16. serializer_class = BookSerializer
  17. filter_backends = [CommonFilter] # 可以定制多个,从左往右,依次执行

需求:

  1. # 查询价格大于100的所有图书
  2. http://127.0.0.1:8000/api/v1/books/?price_gt=100

定义一个过滤类,继承BaseFilterBackend,重写filter_queryset方法

编写过滤类:

queryset参数存放所有模型对象。

配置多个过滤类,会依次从左往右执行:

如果想在自定义过滤类中实现类属性设置过滤字段,可以通过反射获取类中的属性:

view就是我们的视图类,可以从视图类中获取类属性。

踩坑:

模型类存放的是charfield charfield不支持__gt

排序类

使用drf内置的排序类.

  1. # 内置的就够了
  2. class BookView(ViewSetMixin, ListAPIView):
  3. queryset = Book.objects.all()
  4. serializer_class = BookSerializer
  5. filter_backends = [OrderingFilter]
  6. ordering_fields = ['price']
  7. # 支持的查询方法:
  8. http://127.0.0.1:8000/api/v1/books/?ordering=price
  9. http://127.0.0.1:8000/api/v1/books/?ordering=-price
  10. http://127.0.0.1:8000/api/v1/books/?ordering=-id,price

先将排序类配置到filter_backends

再设置排序字段:price

按照价格排序ordering=price

如下是按照价格升序.

按照价格逆序ordering=-price

支持多个排序:比如先按照价格排序,再按照购买量排序。

只需要在视图类配置排序字段:

ordering_field = ['price','sales']

前端格式如下:

http://127.0.0.1:8000/api/v1/books/?ordering=-price,sales按照逗号隔开.(先按照价格逆序,在按照销售额升序)

分页类

  1. # 分页,只有查询所有接口,才有分页
  2. # drf内置了三个分页器,对应三种分页方式
  3. #内置的分页类不能直接使用,需要继承,定制一些参数后才能使用
  4. # 分页使用,自定义一个分页类(三种)
  5. class CommonPageNumberPagination(PageNumberPagination):
  6. page_size = 2 # 每页显示2条
  7. page_query_param = 'page' # page=10 查询第10页的数据,每页显示2条
  8. page_size_query_param = 'size' # page=10&size=5 查询第10页,每页显示5条
  9. max_page_size = 5 # 每页最大显示10条
  10. # LimitOffset
  11. class CommonLimitOffsetPagination(LimitOffsetPagination):
  12. default_limit = 3 # 每页显示2条
  13. limit_query_param = 'limit' # limit=3 取3条
  14. offset_query_param = 'offset' # offset=1 从第一个位置开始,取limit条
  15. max_limit = 5
  16. # offset=3&limit=2 0 1 2 3 4 5
  17. # app 用下面
  18. class CommonCursorPagination(CursorPagination):
  19. cursor_query_param = 'cursor' # 查询参数
  20. page_size = 2 # 每页多少条
  21. ordering = 'id' # 排序字段
  22. # 配置在视图类上即可
  23. class BookView(ViewSetMixin, ListAPIView):
  24. queryset = Book.objects.all()
  25. serializer_class = BookSerializer
  26. permission_classes = []
  27. authentication_classes = []
  28. throttle_classes = []
  29. # 之前的东西一样用 ,内置的分页类不能直接使用,需要继承,定制一些参数后才能使用
  30. # pagination_class = PageNumberPagination
  31. #基本分页方式(基本是这种,网页端):http://127.0.0.1:8000/api/v1/books/?page=2&size=3
  32. # pagination_class = LimitOffsetPagination
  33. # 偏移分页 http://127.0.0.1:8000/api/v1/books/?limit=4&offset=1
  34. # 从第一条开始,取4条
  35. pagination_class = CommonCursorPagination
  36. # 游标分页,只能下一页,上一页,不能跳到中间,但它的效率最高,大数据量分页,使用这种较好

只有查询所有接口,才需要分页。

drf内置三个分页器,对应三种分页方式。

数据10000条给前端,前端卡死了都,所以前端直接拿分好的数据。

类属性添加分页类:

分页属性只能配置一种分页方式。

内置的分页类不能直接用,而需要继承之后,自己定制一些参数,之后才能使用。

PageNumberPagination(网页)

源码:

需要设置四个类属性:



page_size可以写在配置文件中。

四个属性:

可以通过前端的size定制每页显示的条数。size的条数会受到最大条数的限制。

配置分页器:

响应中包含前页和后页:

第一页显示三条:

LimitOffsetPagination

也是配置类属性:

会将所有的数据排序:相当于做切片。

第一页:

从第一条数据开始拿,往后面拿4条数据:

CursorPagination(大数据,app)

游标分页源码:

具体使用:类属性重复会先用哪个?

游标分页,只能下一页,上一页,不能跳到中间,他的效率最高。适合大数据量的时候。

前面的分页, 是将数据从头开始检索,数据量越大,越慢,效率越低.

在分页时维护一个游标。

返回地址带链接:

游标分页默认的配置:

游标分页默认按照时间排序,如果没有在分页类中定义ordering属性就会报错。

这是因为ordering必须是表的字段,比如我们的表里肯定有id字段,所以可以设置ordering为'id':

【Django drf】认证类 权限类 频率类 过滤类 排序类 分页类的更多相关文章

  1. drf-认证、权限、频率、过滤、排序、分页

    1.认证组件 1.1 局部认证 1.首先写两个接口,一个查询单个一个查询所有,我们利用视图扩展类和视图子类写在一个视图类上: views.py: from rest_framework.viewset ...

  2. drf权限,频率,过滤,排序,异常处理

    目录 一.权限 1 权限源码分析 2 自定义权限类 3 内置权限类 二.频率 1 内置频率设置 三.过滤 四.排序 五.异常处理 一.权限 1 权限源码分析 # APIView---->disp ...

  3. rest-framework框架——认证、权限、频率组件

    一.rest-framework登录验证 1.models.py添加User和Token模型 class User(models.Model): name = models.CharField(max ...

  4. restful(3):认证、权限、频率 & 解析器、路由控制、分页、渲染器、版本

    models.py中: class UserInfo(models.Model): name = models.CharField(max_length=32) psw = models.CharFi ...

  5. Rest_Framework之认证、权限、频率组件源码剖析

    一:使用RestFramwork,定义一个视图 from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet ...

  6. django-rest-framework 基础三 认证、权限和频率

    django-rest-framework 基础三 认证.权限和频率 目录 django-rest-framework 基础三 认证.权限和频率 1. 认证 1.1 登录接口 1.2 认证 2. 权限 ...

  7. DRF 认证、权限、限制

    DRF 认证.权限.限制   认证: 定义一个用户表和一个保存用户的Token表 # ======================day96======================= class ...

  8. drf框架 - 三大认证组件 | 认证组件 | 权限组件 | 频率组件

    RBAC 基于用户权限访问控制的认证 - Role-Based Access Control Django框架采用的是RBAC认证规则,RBAC认证规则通常会分为 三表规则.五表规则,Django采用 ...

  9. django身份认证、权限认证、频率校验使用及源码分析

    一. 身份认证源码分析 1.1 APIView源码的分析 APIView源码之前分析过https://www.cnblogs.com/maoruqiang/p/11135335.html,里面主要将r ...

  10. DRF比Django的认证和权限高在哪里

    Django可以用LoginRequiredMixin和PermissionRequiredMixin给类视图添加认证和权限,DRF做了高级封装,提供了更简洁的实现方式.我们通过继续学习官网教程来进行 ...

随机推荐

  1. 题解 CF637B

    题目大意: 维护个栈,去重保留最上层 题目分析: 啥也不是,数组模拟 \(\text{stack} + \text{unordered\_map}\) 直接秒掉. 复杂度 \(O(n)\) 代码实现: ...

  2. Util应用框架基础(六) - 日志记录(四) - 写入 Exceptionless

    本文是Util应用框架日志记录的第四篇,介绍安装和写入 Exceptionless 日志系统的配置方法. Exceptionless 是一个日志管理系统,使用 Asp.Net Core 开发,比 Se ...

  3. 【Flutter】一文读懂混入类Mixin

    [Flutter]一文读懂混入类Mixin 基本介绍 Mixin是一种有利于代码复用,又避免了多继承的解决方案. Mixin 是面向对象程序设计语言中的类,提供了方法的实现,其他类可以访问 Mixin ...

  4. 这些新项目一定不要错过「GitHub 热点速览」

    本周 GitHub 热点上榜的项目有不少的新面孔,比如搞电子商务的 eShop,还有处理表数据的 onetable.还有用来方便处理数据同步问题的 loro,以及网易新开源的 tts 项目 Emoti ...

  5. python判断素数

    def slowsnail(num): count = num // 2 while count > 1: if num % count == 0: print('%d最大的约数是%d' % ( ...

  6. [HDU4117] GRE

    Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the mos ...

  7. Tensorflow2.0使用Resnet18进行数据训练

    在今年的3月7号,谷歌在 Tensorflow Developer Summit 2019 大会上发布 TensorFlow 2.0 Alpha 版,随后又发布了Beta版本. Resnet18结构 ...

  8. catcat-new【目录穿透+特殊文件】

    catcat-new[目录穿透+特殊文件] 题目界面 点击任何一只猫猫,发现路径泄露: 解题步骤 测试目录遍历漏洞 路径: ?file=../../../../etc/passwd 成功读取到pass ...

  9. Scrapy在pipeline中集成mongodb

    settings.py中设置配置项 MONGODB_HOST = "127.0.0.1" MONGODB_PORT = 27017 MONGODB_DB_NAME = " ...

  10. NetSuite 开发日记 —— 非空判断

    使用N/util模块进行非空判断,N/util模块说明:https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_45 ...