三大认证源码分析
权限类的执行源码
已知在drf中ApiView 在执行视图类方法之前先进行了3大认证
1.在执行视图类方法前 先进行了三大认证 在apiview中的dispatch方法中 497行左右
try:
self.initial(request, *args, **kwargs)
# 只有通过了3大认证 才会执行下面的代码
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
2.查看initial方法发现:
self.perform_authentication(request)
self.check_permissions(request)
# 执行了该方法 检查权限
self.check_throttles(request)
3.查看check_permissions方法
def check_permissions(self, request):
for permission in self.get_permissions():
# 发现这里又执行了get_permissions()方法,查看该方法发现
# 这里其实就是获取到了我们设定的权限类并执行了
if not permission.has_permission(request, self):
# 执行我们重写的has_permission如果返回ture就是false这里取反了
# ture就不需要执行if里面的代码了 直接循环下一个权限类
# 如果是false那这里取反就是true那就要执行if内代码
self.permission_denied(
# 执行.permission_denied
# 结果raise抛异常
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
#总结:
APIView---dispatch----initial---check_permissions
里面取出配置在视图类上的权限类,实例化得到对象,一个个执行对象的has_permission方法,如果返回False,就直接结束,进行permission_denied方法
如果视图类上不做权限类配置 默认使用配置文件中的api_settings.DEFAULT_PERMISSION_CLASSES
认证类的执行源码
1.查看initial方法发现:
self.perform_authentication(request)
request.user
# 该方法返回了一个request.user 分析request.user
2.查看request类中的user方法
def user(self):
# 这里面的self是 request类的对象
if not hasattr(self,'_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
3.执行了 self._authenticate()方法
在request类中的_authenticate()方法
def _authenticate(self):
for authenticator in self.authenticators:
# self.authenticators就是我们配置的认证类 通过for循环来执行认证
# 是request的类在初始化生成对象的时候传入的authenticators
try:
user_auth_tuple = authenticator.authenticate(self)
# 这里执行了我们配置的认证类,然后我们的认证类会返回用户对象
# 和token 如果有返回两个就成功走下面的代码,结束了for循环
# 如果没有 返回的none 那就继续循环执行下一个认证类
except exceptions.APIException:
# 这里捕获了我们抛的异常
self._not_authenticated()
# 这里执行了没有认证通过
raise
if user_auth_tuple is not None:
# 通过拿到我们认证类给的 user对象 然后加入了self中
# 这样就明白了为什么 request中可以通过.user方式拿到对象
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
# 解压赋值 将我们返回的对象给了self.user,我们返回的token给了self.auth
return
self._not_authenticated()
# self.authenticators 是这样来的去 在Request类的init中找152行左右
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
.....
self.authenticators = authenticators or ()
# 什么时候调用Reqeust的__init__?---》APIVIew的dispatch上面的492行的:request = self.initialize_request(request, *args, **kwargs)-----》385行----》
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
# 这里传入了authenticators,所以之前才可以self.authenticators
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# 总结:
1 配置在视图类上的认证类,会在执行视图类方法之前执行,在权限认证之前执行
不然权限类拿不到user对象 无法核实权限
2 自己写的认证类,可以返回数据对象/数据 2个值 或 None
多认证类时返回none会执行下一个认证类
3 认证通过后可以从request.user 取出当前登录用户(前提是你要在认证类中返回)
频率类的执行源码
1.在执行视图类方法前 先进行了三大认证 在apiview中的dispatch方法中 497行左右
try:
self.initial(request, *args, **kwargs)
# 只有通过了3大认证 才会执行下面的代码
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
2.查看initial方法发现:
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
# 查看权限类执行流程
3.# APIView 的352行
def check_throttles(self, request):
throttle_durations = []
# 先定义了一个空列表
for throttle in self.get_throttles():
# self.get_throttles()执行我们配置的频率类对象
if not throttle.allow_request(request, self):
# 用我们的频率类来执行.allow_request方法,如果返回false就是超频了,无法再接着往下走了
# 如果是true 没有超频就可以接着走
throttle_durations.append(throttle.wait())
if throttle_durations:
durations = [
duration for duration in throttle_durations
if duration is not None
]
duration = max(durations, default=None)
self.throttled(request, duration)
# 总结:
-我们写的频率类:继承BaseThrottle,重写allow_request,在内部判断,如果超频了,就返回False,如果没超频率,就返回True
基于APIView编写分页
定制分页字段
from rest_framework.viewsets import ViewSet
编写分页功能需要继承 ViewSetMixin 和 apiview或其子类
class books(ViewSet):
def list(self, request):
books = Book.objects.all()
paginator = CommonLimitOffsetPagination()
# 1 实例化得到一个分页类的对象
page = paginator.paginate_queryset(books, request, self)
# 2 调用分页类对象的paginate_queryset方法来完成分页,返回的page是 要序列化的数据,分页好的
if page is not None:
serializer = BookSerializer(instance=page, many=True)
return Response({
'total': paginator.count,
# 这是第几页的意思
'next': paginator.get_next_link(),
# 下一页地址
'previous': paginator.get_previous_link(),
# 上一页地址
'results': serializer.data
# 本页数据
})
# 3 返回数据,
全局异常处理
应用下创建处理异常文件 exception.py
目标:无论是主动抛异常还是程序运行错误,都返回固定的格式,并记录日志
# APIView--->dispatch--->三大认证,视图类的方法,如果出了异常,会被异常捕获,捕获后统一处理
# drf 内置了一个函数,只要上面过程出了异常,就会执行这个函数,这个函数只处理的drf的异常
# 但是我们代码中的异常 程序报错无法捕获
# 判断处理的结果(返回值)response,有值代表drf已经处理了,None代表需要自己处理
先将异常处理交给rest_framework.views的exception_handler去处理
def common_exception(exc, context):
res = exception_handler(exc, context)
times = datetime.datetime.now()
# 获取错误发生时间
user_obj = context.get('request')
# 拿到错误对象
view = context.get('view')
# 获取发生错误的视图函数
ip = user_obj.META.get('REMOTE_ADDR')
# 获取请求的id
method = user_obj.method
# 获取请求方式
user_id = user_obj.user.pk
# 获取用户id
print(f'时间:{times}--ip:{ip}--请求方式--{method}--错误模块:{view}--错误信息:{exc}--用户id:{user_id}')
if res:
# 如果有值说明是drf的异常 已经被处理了
res = Response(data={'code': '9999', 'msg': res.data.get('detail', '请联系系统管理员')})
else:
# 没值说明的是django的错误
res = Response(data={'code': '8888', 'msg': '系统错误请联系系统管理员'})
return res
sttings.py文件--------------
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.authentications.LoginAuth'],
'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.CommonPermission'],
'DEFAULT_THROTTLE_RATES': {
'booksListThrottling': '5/m',
},
'EXCEPTION_HANDLER': 'app01.exceptions.common_exception',
# 在配置文件中配置一下刚刚写的错误方法
}
标签:get,self,request,认证,源码,user,执行,三大,drf
From: https://www.cnblogs.com/moongodnnn/p/17103322.html