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
     

     




  • 相关阅读:
    GTK+ 3.6.2 发布,小的 bug 修复版本
    RunJS 新增 Echo Ajax 测试功能
    Mozilla 发布 Popcorn Maker,在线创作视频
    Sina微博OAuth2框架解密
    Mina状态机State Machine
    Mozilla 发布 Shumway —— 纯JS的SWF解析器
    Code Browser 4.5 发布,代码浏览器
    ROSA 2012 "Enterprise Linux Server" 发布
    ltrace 0.7.0 发布,程序调试工具
    Artifactory 2.6.5 发布,Maven 扩展工具
  • 原文地址:https://www.cnblogs.com/JackShi/p/13024932.html
Copyright © 2011-2022 走看看