zoukankan      html  css  js  c++  java
  • rest framework

    1. 安装

       pip install djangorestframework

    2. 认证源码及流程

    (注意局部配置的类会覆盖全局配置)

    创建一个类的时候需要继承APIView,该类为View的子类
    
    class DogView(APIView):
      pass

    1. 首先调用该视图类的时候回执行dispatch方法进行反射。在APIView中查找,该方法中request参数如下
      # 对原生的request进行加工
      # 新的request比原request增加了一些功能
      # 获取原生 requestrequest._request
      # 获取认证类对象 request.authenticators
      # 1. 封装Request
      request = self.initialize_request(request, *args, **kwargs)
    2. 查看self.initialize_request()方法,它为原生request添加了功能
    3. dispatch方法中如下认证代码
      try:
       # 认证
       self.initial(request, *args, **kwargs)
    4. 查看self.initial()方法,里面有:
      self.perform_authentication(request)
    5. 查看self.perform_authentication()方法,
      request.user # 此时的request是封装后的Request对象
    6. 查看Request的user属性
      @property
      def user(self):
       """
       Returns the user associated with the current request, as authenticated
       by the authentication classes provided to the request.
       """
       if not hasattr(self, '_user'):
       with wrap_attributeerrors():
       # 获取认证对象,进行一步步的认证
       self._authenticate()
      return self._user

    7. self._authenticate()中
      # authenticators是Request中的一个参数,是一个列表,可以修改,这个列表是get_authenticators()方法产生的类加括号实例化的对象列表
      # 该方法在执行后会有三种结果:
      # 1. authenticate抛出异常:执行self._not_authenticated()方法
      # 2. 有返回值,且必须是元组,分别赋值给request.user,request.auth
      # 3. 返回None,跳过该验证类,进行下一个for循环的验证类,如果所有类的方法都返回None,那么会继续执行self._not_authenticated()方法
      # 4. self._not_authenticated()方法会给request.user赋值为AnonymousUser,request.auth赋值为None
      def _authenticate(self):
       """
       Attempt to authenticate the request using each authentication instance
       in turn.
      """
       for authenticator in self.authenticators:
       try:
       user_auth_tuple = authenticator.authenticate(self)
       except exceptions.APIException:
      self._not_authenticated()
       raise

      if user_auth_tuple is not None:
      self._authenticator = authenticator
      self.user, self.auth = user_auth_tuple # 分别赋值
      return

      self._not_authenticated()


    9. 认证类的默认列表是authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    在api_settings中发现,可以通过在项目settings中配置名为REST_FRAMEWORK的变量来配置认证类
    def reload_api_settings(*args, **kwargs):
    setting = kwargs['setting']
    if setting == 'REST_FRAMEWORK':
    api_settings.reload()

    10. 综上,配置认证类有两种方法
    # 1. 在项目settings中配置,作用于全局,所有继承APIView的视图都要进行认证
    # rest framework配置
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.Authentication', ],  # 将认证类放在app下的utils.auth中
        'UNAUTHENTICATED_USER': None,  # request.user
        'UNAUTHENTICATED_TOKEN': None,  # request.auth
    }

    # 2. 在需要修改的视图中配置
    # 只需加上authentication_classes = []即可不对其进行认证
    class AuthView(APIView):
    """
    用户登录业务
    """
    authentication_classes = []
    # 登录一般用post
    def post(self, request, *args, **kwargs):
        pass
    11. 所有的认证类都放到了utils中与业务视图分开
    from rest_framework import exceptions
    from rest_framework.authentication import BaseAuthentication
    
    from api import models
    
    
    class Authentication(BaseAuthentication):  # 这里的父类也可以写成APIView,但是现在的写法更正规
        def authenticate(self, request):
            token = request._request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed('用户认证失败')
    
            # 在rest framework中会将两个字段赋值给request作为属性,以供后续操作使用
            return token_obj.user, token_obj
    
    

     3. 权限使用

    (注意局部配置的类会覆盖全局配置)

    1. 步骤与认证类似
    2. 在APIView中找到嗲patch方法
    3. 封装request对象
    4. try中有self.check_permissions(request),点开查看
    5. check_permissions()方法有两种结果:
        1. 用户以被授权,方法什么都不做,通过权限校验
        2. 用户没有被授权, 方法抛出异常

    6. 使用步骤1:定义认证类(需要重写has_permission方法)
      如果has_permission方法返回TRUE,不执行之后代码,验证通过,
      如果返回false,执行后续代码,抛出异常,认证失败
    
    
    from rest_framework.permissions import BasePermission


    class
    MyPermission(BasePermission): # 这里的父类也可以继承APIView,现在的写法更正规 message = 'SVIP才能访问' # 拒绝访问之后返回给用户看的信息 def has_permission(self, request, view): """ 自定义权限,只用svip才能访问 :param request: :param view: :return: """ if request.user and request.user.user_type == 3: return True else: return False class MyPermission1(BasePermission): # 父类这样写更正规 message = '普通用户, VIP才能访问' def has_permission(self, request, view): """ 自定义权限,只用svip才能访问 :param request: :param view: :return: """ if request.user and request.user.user_type in [1,2]: return True else: return False

    7. 使用步骤2:全局使用或局部使用

    class OrderView(APIView):
        """
        订单相关业务
        """
        permission_classes = [MyPermission, ]  # 局部使用
    
        def get(self, request, *args, **kwargs):
        pass

    settings.py中配置全局使用
    # rest framework配置
    REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.Authentication', ],
    'UNAUTHENTICATED_USER': None, # request.user
    'UNAUTHENTICATED_TOKEN': None, # request.auth
    'DEFAULT_PERMISSION_CLASSES': ['api.utils.permission.MyPermission',] # 将权限类放在app下的utils.permission文件中
    }
     

    4. 限制访问频率

    (注意局部配置的类会覆盖全局配置)

    1. 自定义访问频率限制方法, 使用时在全局配置或者在视图配置throttle_classes = [...]
    class VisitThrottle(object):
        """
        60s内访问3次
        """
        def __init__(self):
            self.history = None
    
        def allow_request(self, request, view):
            remote_addr = request.META.get('REMOTE_ADDR')
            ctime = time.time()
            if remote_addr not in VISIT_RECORD:
                VISIT_RECORD[remote_addr] = [ctime, ]
                return True
            history = VISIT_RECORD.get(remote_addr)
            self.history = history
    
            while history and history[-1] < ctime - 60:
                history.pop()
    
            if len(history) < 3:
                history.insert(0, ctime)
                return True
            else:
                return False
    
            # return True  # 表示可以继续访问
            # return False  # 表示访问频率过高,限制访问
    
        def wait(self):
            """
            还要多久才能访问
            :return:
            """
            ctime = time.time()
            return 60 - (ctime - self.history[-1])

    2. 使用模块自带的频率限制功能

    throttle.py
    from rest_framework.throttling import SimpleRateThrottle
    
    
    class VisitThrottle(SimpleRateThrottle):
        # 在settings中配置
        scope = 'visit'
    
        # 仅有这个方法需要我们自己重写,此处返回ip
        def get_cache_key(self, request, view):
            return self.get_ident(request)
    
    
    class UserThrottle(SimpleRateThrottle):
        scope = 'user'
    
      # 此处返回用户名 def get_cache_key(self, request, view): return request.user.username

    settings.py

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.Authentication', ],
        'UNAUTHENTICATED_USER': None,  # request.user
        'UNAUTHENTICATED_TOKEN': None,  # request.auth
        'DEFAULT_PERMISSION_CLASSES': ['api.utils.permission.MyPermission', ],
        
        'DEFAULT_THROTTLE_RATES': {
            'visit': '5/m',  # 每分钟5次
            'user': '20/m',
        },
        'DEFAULT_THROTTLE_CLASSES': ['api.utils.throttle.UserThrottle', ]  # 配置全局频率限制
    
    }

    局部配置
    class OrderView(APIView):
    """
    订单相关业务
    """
      throttle_classes = [UserThrottle, ]

    def get(self, request, *args, **kwargs):
        pass
     

     




  • 相关阅读:
    cookie的使用
    给定一个数组和一个目标值,找出和为目标值的整数,并返回他们的下标
    String详解
    阳哥讲面试题(四)生产调优
    springboot项目调优(针对特性的服务启动,定制化诉求)
    intern() 方法
    阳哥讲面试题(四)OOM,GC算法,垃圾收集器
    阳哥讲面试题(三)JVM,GC
    阳哥讲面试题(二)队列,线程池
    Semaphore用法
  • 原文地址:https://www.cnblogs.com/JackShi/p/13024932.html
Copyright © 2011-2022 走看看