6. 认证组件、权限组件、限流组件、过滤组件、排序组件

 本节内容:

  一 、认证组件Authentication

    1.1 认证组件介绍

    1.2  自定义认证组件

  二 、权限组件 Permissions

    2.1 使用

    2.2 提供的权限

    2.3 自定义权限

  三 、限流组件Throttling

    3.1 使用

    3.2 可选限流类

    3.3 实例

    3.4 自定义频率组件

  四、过滤组件  Filtering

  五 、排序

为了方便接下来的学习,我们创建一个新的子应用 four

python manage.py startapp four

因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员.

python manage.py createsuperuser
填一下用户名、邮箱和密码
root
1232@qq.com
123

 创建管理员以后,访问admin站点,先修改站点的语言配置

settings.py

 访问admin 站点效果:

一 、认证组件Authentication

1.1 认证组件介绍

认证定义:已经登录的用户,再次访问时,系统会校验是否登陆过,登录过直接访问获取数据,否则需要输入用户、密码,这个过程叫做认证

可以在配置文件中配置全局默认的认证方案

from rest_framework import settings中可以看到它默认使用的

在settings配置文件中,我们可以进行下面的配置来覆盖默认配置
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
      #哪个写在前面,优先使用哪个认证
        'rest_framework.authentication.SessionAuthentication',  
    # session认证,admin后台其实就使用的session认证,其实接口开发很少用到session认证,#
     所以我们通过配置可以改为其他认证,比如后面项目里面我们用到jwt,JSON WEB TOKEN认证,或者一些配合redis的认证
'rest_framework.authentication.BasicAuthentication',
    # 基本认证,工作当中可能一些测试人员会参与的话,他们会将一些认证数据保存在内存当中,然后验证的,我们基本上用不上 ) }

看效果:能够看到我们当前的登陆用户了就,其实不配置也能看到,因为我们并没有修改认证系统

 也可以在每个视图中通过设置authentication_classess属性来设置,比如说我们很多接口的数据都是可以让别人获取数据的,但是有可能有些接口是调用给别人网站的,有可能到时候我们就需要一些单独的认证了

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
    # 类属性
    authentication_classes = [SessionAuthentication, BasicAuthentication] #也可以写成元祖形式的,到时候我们使用我们自己开发的认证组件的时候,就需要自己写一个认证组件类,然后写在列表中来使用
    ...

1.2  自定义认证组件

1.2.1 写一个认证类

需要继承一个基类 BaseAuthentication 然后重写基类中的方法

return 返回的两个值分别为用户信息(xx)和其他信息(oo),可以用一下方法获取
request.user = 'xx'  
request.token = 'oo'
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class APIAuth(BaseAuthentication):

    def authenticate(self, request):
        print(request) #<rest_framework.request.Request object at 0x1142bd190>   request.user


        if 1:
            return 'xx','oo'  #request.user = 'xx'  request.auth = 'oo' request.token = 'oo'
        
        else:
            raise AuthenticationFailed('认证失败')

全局使用,settings配置文件中使用

 REST_FRAMEWORK = {
      'DEFAULT_AUTHENTICATION_CLASSES': (
          ...
          'four.utils.auth.APIAuth',  #类的路径

      ),
    }

局部视图中使用:

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from four.utils.auth import APIAuth

class AuthAPIView(APIView):
    authentication_classes = [APIAuth,]
    def get(self,request):
        print('>>>>',request.user)  #AnonymousUser  匿名用户,假用户
        print('>>>>',request.auth)  #AnonymousUser  匿名用户,假用户
        #>>>> root
        return Response({'msg':'hello'})
 1 class UserAuth():
 2    def authenticate_header(self,request):
 3          pass
 4 #authenticate方法固定的,并且必须有个参数,这个参数是新的request对象,不信,看源码
 5     def authenticate(self,request):
 6                 print('搞事情')
 7         if 1:
 8         #源码中会发现,这个方法会有两个返回值,并且这两个返回值封装到了新的request对象中了,request.user-->用户名 和 request.auth-->token值,这两个值作为认证结束后的返回结果
 9             return "chao","asdfasdfasdf"
10 
11 class BookView(APIView):
12     #认证组件肯定是在get、post等方法执行之前执行的,还记得源码的地方吗,这个组件是在dispatch的地方调用的,我们是上面写个UserAuth类
13     authentication_classes = [UserAuth,] #认证类可以写多个,一个一个的顺序验证
14     def get(self,request):
15         '''
16         查看所有书籍
17         :param request:
18         :return:
19         '''
20         #这样就拿到了上面UserAuth类的authenticate方法的两个返回值
21         print(request.user)  
22         print(request.auth)
23         book_obj_list = models.Book.objects.all()
24         s_books = BookSerializers(book_obj_list,many=True)
25         return Response(s_books.data)
示例

二 、权限组件 Permissions

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断

  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

  • 只有继承APIView的的类才可以使用,使用Django原有的view的不可以使用

2.1 使用

可以在配置文件中全局设置默认的权限管理类,如

REST_FRAMEWORK = {
    ....
    
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated', #登录状态下才能访问我们的接口,可以通过退出admin后台之后,你看一下还能不能访问我们正常的接口就看到效果了
    )
}

如果未指明,则采用如下默认配置

from rest_framework import permissions
'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny', #表示任何人都可以进行任何的操作,没做限制
)

也可以在具体的视图中通过permission_classes属性来设置,如

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)
    ...

2.2 提供的权限

  • AllowAny 允许所有用户

  • IsAuthenticated 仅通过认证的用户

  • IsAdminUser 仅管理员用户(可以通过admin创建一个用户进行测试)

  • IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。

from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]

2.3 自定义权限

如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部

  • .has_permission(self, request, view)

    是否可以访问视图, view表示当前视图对象

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

    是否可以访问数据对象, view表示当前视图, obj为数据对象

例如:

在当前子应用下,创建一个权限文件permissions.py中声明自定义权限类:

 

from rest_framework.permissions import BasePermission

class IsXiaoMingPermission(BasePermission):
    def has_permission(self, request, view):
      
        if( request.user.username == "xiaoming" ):
            return True
from .permissions import IsXiaoMingPermission
class StudentViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    permission_classes = [IsXiaoMingPermission]
认证组件和权限组件的使用流程
认证组件:  
    1 drf默认自带的认证组件是session那一套
    2 自定认证组件
        a: 项目中创建一个文件夹,比如叫做xx
        b: 在xx文件夹中创建一个py文件,比如叫做xxx.py
        c: 在xxx.py文件中定义一个类,名称随意,比如叫做 class Auth(BaseAuthentication),需要继承drf提供的基础认证类
            from rest_framework.authentication import BaseAuthentication

        d:在认证类中就可以定义一个authenticate 方法
            def authenticate(self,request):
                if 1:
                    return "chao","asdfasdfasdf"

                
        e: 全局使用: 在settings.py配置文件中来指定这个类的路径
                REST_FRAMEWORK = {
                    # 'DEFAULT_AUTHENTICATION_CLASSES': (
                    #     'xx.xxx.Auth',  # 自定义认证类

                    # ),
                    


                }
        f:局部使用: 在视图类中通过类属性来指定
           class IndexView(APIView):
            authentication_classes = [Auth, ]
            def get(self, request):
                print(request.user)
                print(request.auth)
                return Response({'xx': '老白'})
权限组件
    :过程基本面一致
    
认证组件和权限组件的使用流程

三 、限流组件Throttling

可以对接口访问的频次进行限制,以减轻服务器压力。

一般用于付费购买次数,投票等场景使用.

3.1 使用

可以在配置文件中,使用DEFAULT_THROTTLE_CLASSESDEFAULT_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, hourday来指明周期。

源码:
{'s': 1, 'm': 60, 'h': 3600, 'd': 86400} m表示分钟,可以写m,也可以写minut

也可以在具体视图中通过throttle_classess属性来配置,如

from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

class ExampleView(APIView):
    throttle_classes = (UserRateThrottle,)
    ...

3.2 可选限流类

1) AnonRateThrottle

限制所有匿名未认证用户,使用IP区分用户。

使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次

2)UserRateThrottle

限制认证用户,使用User id 来区分。

使用DEFAULT_THROTTLE_RATES['user'] 来设置频次

3.3 实例

全局配置中设置访问频率

 'DEFAULT_THROTTLE_RATES': {
        'anon': '3/minute',
        'user': '10/minute'
    }
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]
    throttle_classes = (UserRateThrottle,)

3.4 自定义频率组件

from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
import time
from rest_framework import exceptions
visit_record = {}
class VisitThrottle(BaseThrottle):
    # 限制访问时间
    VISIT_TIME = 10
    VISIT_COUNT = 3

    # 定义方法 方法名和参数不能变
    def allow_request(self, request, view):
        # 获取登录主机的id
        id = request.META.get('REMOTE_ADDR')
        self.now = time.time()

        if id not in visit_record:
            visit_record[id] = []

        self.history = visit_record[id]
        # 限制访问时间
        while self.history and self.now - self.history[-1] > self.VISIT_TIME:
            self.history.pop()
        # 此时 history中只保存了最近10秒钟的访问记录
        if len(self.history) >= self.VISIT_COUNT:
            return False
        else:
            self.history.insert(0, self.now)
            return True

    def wait(self):
        return self.history[-1] + self.VISIT_TIME - self.now

四、过滤组件  Filtering

对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。

pip install django-filter

在配置文件中增加过滤后端的设置:

INSTALLED_APPS = [
    ...
    'django_filters',  # 需要注册应用,
]

REST_FRAMEWORK = {
    ...
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

在视图中添加filter_fields属性,指定可以过滤的字段

例如:127.0.0.1:8000/four/students/?sex=1
可以在访问上面的路径查询sex=1的所有数据
class StudentListView(ListAPIView):
    # def get:return self.list()  查询所有数据
    queryset = Student.objects.all()
    
    serializer_class = StudentSerializer
    filter_fields = ('age', 'sex')

# 127.0.0.1:8000/four/students/?sex=1

五 、排序

对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序

使用方法:

在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。

前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。

示例:

class StudentListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ('id', 'age')

# 127.0.0.1:8000/books/?ordering=-age 
# 必须是ordering=某个值
# -id 表示针对id字段进行倒序排序
# id  表示针对id字段进行升序排序

如果需要在过滤以后再次进行排序,则需要两者结合!

from rest_framework.generics import ListAPIView
from students.models import Student
from .serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend #需要使用一下它才能结合使用
class Student3ListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_fields = ('age', 'sex')
    # 因为filter_backends是局部过滤配置,局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明,
    # 否则过滤功能会失效
    filter_backends = [OrderingFilter,DjangoFilterBackend]
    ordering_fields = ('id', 'age')
    
# 127.0.0.1:8000/books/?sex=1&ordering=-age 

 

原文地址:https://www.cnblogs.com/yj0405/p/14579876.html