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
 

 




原文地址:https://www.cnblogs.com/JackShi/p/13024932.html