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