一、认证的流程
- 首先我们采用的cbv的模式去写。去看以下加工后的request里面包含了什么?
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
class DogView(APIView):
def get(self, request, *args, **kwargs):
return HttpResponse('获取狗!')
def post(self, request, *args, **kwargs):
return HttpResponse('更新狗')
其实APIView继承的是Django的View,只不过又在此基础上又丰富了一些。那么现在带大家来看一下源码!
基于CBV的写法,那么当我们访问接口url的时候,那么首先执行的是dispath方法。
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
## 对原生的request进行加工(丰富了一些功能)
request = self.initialize_request(request, *args, **kwargs)
# request._request 获取原生request
# request.authenticators 获取认证类的对象
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
# 此处利用了Python的反射函数
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
其中有一行是对原生的request进行加工,那么initialize_request函数又做了什么?
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
其中request是原始的request,今天的主角来了,就是authenticators。那么它又调用了get_authenticators(),
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
# 使用了列表生成式,那么我们得到的是一个 对象的list。
return [auth() for auth in self.authentication_classes]
那么self.authentication_classes 又是什么呢?
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
从代码可知,这是django的配置文件里提供的DEFAULT_AUTHENTICATION_CLASSES
那么现在我们已经知道: request里已经包含了最初的request(request._request), 以及认证后的对象[], (request.authenticators)
- 接下来到了try语句里面:
self.initial(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
# 主要看下面这一句 !!! 看这,来看下边!
# 主要看下面这一句 !!! 看这,来看下边!
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
def perform_authentication(self, request):
"""
Perform authentication on the incoming request.
Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user
此时又调用了request.user, 因为带装饰符,所以以属性的方法调用,而此时self指的是Request的实例,
@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
此时又调用了_authenticate方法
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()
各位同学,还记得authenticators这个么? 这个就是认证对象的list,那么从代码可知,我们的这个对象包含一个authenticate方法,所以所以所以我们自己定义的时候,就主要是定义这个方法!
哇喔!!! 整体步骤我们理清了,那么如何来完成一个只有登录之后才可以访问的接口api呢。
二、实现
self.authentication_classes 当我们类提供authentication_classes这个属性时,那么就不会读取配置文件默认的。
再来看以下代码:
from rest_framework.views import APIView
from rest_framework.authentication import BasicAuthentication
from rest_framework import exceptions
class MyAuthentication(object):
def authenticate(self, request):
token = request._request.GET.get('token')
if not token:
raise exceptions.AuthenticationFailed('用户认证失败')
return ('alex', None)
def authenticate_header(self, val):
pass
class DogView(APIView):
authentication_classes = [MyAuthentication, ]
def get(self, request, *args, **kwargs):
return HttpResponse('获取狗!')
def post(self, request, *args, **kwargs):
return HttpResponse('更新狗')
现在明白怎么回事了么? MyAuthentication类里面的authenticate_header这个函数虽然是空的代码,但是是强制要写的~ 至于为什么, tell me why?
欢迎大家一起找我探讨Python的代码,前一段时间因为公司实在是太忙了,所以更新不太及时,各位请见谅~~~~~
网友评论