zoukankan      html  css  js  c++  java
  • 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 

     

  • 相关阅读:
    软工实践总结
    Beta总结
    beta冲刺6/7
    beta冲刺5/7
    Beta冲刺4/7
    beta冲刺3/7
    beta冲刺2/7
    beta冲刺1/7
    答辩总结
    ES6中的块级作用域与函数声明
  • 原文地址:https://www.cnblogs.com/yj0405/p/14579876.html
Copyright © 2011-2022 走看看