pip install djangorestframework
urls.pyhtml
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^dog/', views.DogView.as_view()) ]
views.pypython
from rest_framework.views import APIView class DogView(APIView): def get(self, request, *args, **kwargs): # 这里的 request 是rest framework加工以后的 request,再也不是原来的request了 print(request) ret = { 'code': 1000, 'msg': 'xxx' } return HttpResponse(json.dumps(ret), status=201) def post(self, request, *args, **kwargs): return HttpResponse('建立Dog') def put(self, request, *args, **kwargs): return HttpResponse('更新Dog') def delete(self, request, *args, **kwargs): return HttpResponse('删除Dog')
当请求进来,执行 dispatch
,本身没有找父类 APIView
的 dispatch
django
def dispatch(self, request, *args, **kwargs): ... # 省略的内容 self.kwargs = kwargs # 对原生的request进行加工(丰富了一些功能) ''' # 鼠标点进 initialize_request,返回一个对象 return Request( request, # 这里才是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) ''' request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? ...
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) # 返回Request类的一个对象,交给上面的request return Request( request, # 这里才是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), # 这里有个 get_authenticators negotiator=self.get_content_negotiator(), parser_context=parser_context )
问题:若是执行 self.get_authenticators()
,流程是怎样的,哪里是入口?json
''' 应该从 DogView 作入口,由于里面全部传过去的self,都是 DogView 的对象 DogView 没有再往父类找 这里 DogView 没有 get_authenticators(),而且这个方法应该加了s,猜想应该是个复数 鼠标点进去,查看父类 ''' def get_authenticators(self): """ Instantiates and returns the list of authenticators that this view can use. """ return [auth() for auth in self.authentication_classes] ''' 能够看到,返回了一个列表,若是 self.authentication_classes 也是一个列表,而且 self.authentication_classes = [Foo, Bar] 列表里面是两个类,则 [auth() for auth in self.authentication_classes] 就是对每一个类进行实例化 因此谁调用这个 get_authenticators 方法,返回的就是 [Foo, Bar] 的对象 即 [Foo(), Bar()] 固然这些目前只是猜想 '''
根据以上猜想,来查看一下api
''' 这里执行的是 self.authentication_classes,DogView 没有,去父类查看 ''' class APIView(View): ... # 其余的内容 authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES ... ''' 这实际上是读取了 rest_framework的配置文件,是在 APIView中写的 找的时候优先到 DogView 中查找,没有再去父类 '''
如今为 DogView
加上 authentication_classes
,用的就是 DogView
的方法ide
from rest_framework.views import APIView from rest_framework.authentication import BasicAuthentication class DogView(APIView): authentication_classes = [BasicAuthentication, ] # 增长的 def get(self, request, *args, **kwargs): self.dispatch() ret = { 'code': 1000, 'msg': 'xxx' } return HttpResponse(json.dumps(ret), status=201) def post(self, request, *args, **kwargs): return HttpResponse('建立Dog') def put(self, request, *args, **kwargs): return HttpResponse('更新Dog') def delete(self, request, *args, **kwargs): return HttpResponse('删除Dog')
如今增长了 authentication_classes
,回到上面的 get_authenticators
方法,它返回的是 [BasicAuthentication(), ]
对象,再将它交给 Request
对象post
因此新的 Request
对象目前封装了两个值,一个是原生的 request
,一个是 [BasicAuthentication(),]
对象列表this
回到 dispatch
url
def dispatch(self, request, *args, **kwargs): ... # 省略的内容 self.kwargs = kwargs # 对原生的request进行加工(丰富了一些功能) ''' # 鼠标点进 initialize_request,返回一个对象 return Request( request, # 这里才是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) 这里就是 return Request(request, [BasicAuthentication(), ]) ''' request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? ... # 省略的内容
如今是封装进去了,那么要取出,该怎么取呢?(能够经过 request
点出某个属性或方法)能够查看一下 Request
spa
class Request(object): ... # 省略的内容 def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): assert isinstance(request, HttpRequest), ( 'The `request` argument must be an instance of ' '`django.http.HttpRequest`, not `{}.{}`.' .format(request.__class__.__module__, request.__class__.__name__) ) self._request = request # 若是要拿原生的request,须要执行 request._request self.parsers = parsers or () self.authenticators = authenticators or () ... # 省略的内容
# 再回到 dispatch() def dispatch(self, request, *args, **kwargs): ... # 省略的内容 self.kwargs = kwargs # 对原生的request进行加工(丰富了一些功能) ''' # 鼠标点进 initialize_request,返回一个对象 return Request( request, # 这里才是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) 这里就是 return Request(request, [BasicAuthentication(), ]) ''' request = self.initialize_request(request, *args, **kwargs) # 获取原生的request: request._request # 获取认证类的对象: request.authenticators self.request = request self.headers = self.default_response_headers # deprecate? try: # 将上面的 request 放进来,执行initial,DogView没有,去父类查找 self.initial(request, *args, **kwargs) ... # 省略的内容
# 来到 initial # 这里的 request 是封装后的 request def initial(self, request, *args, **kwargs): ... # 省略的内容 # 这里的request是带有原生的request和认证的对象的request # 执行 perform_authentication,DogView 没有,去父类查找 self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)
# 来到 perform_authentication 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
# 经过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() # 注意这里,去 _authenticate return self._user
# 来到 _authenticate def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ # 这里的 self.authenticators 就是加工后的request中的第二个值, # 也就是 [BasicAuthentication对象, ] # 这一步就是循环认证类的全部对象 for authenticator in self.authenticators: try: # 拿到上面的[BasicAuthentication对象, ],里面有个 .authenticate 方法 # 若是这个方法抛出异常,就会被下面的except捕获到 # 若是没有异常,则有返回值(返回值有两种,一个是None,一个是有确切的值) # 有确切的返回值,必须是元组:(request.user, request.auth) # 若是是None,表示本次认证对象不作处理,继续作下一次的循环处理 # 若是全部对象都为None,那么 request.user, request.auth均未赋值 # 等循环玩走最后一步的 self._not_authenticated() # 括号里的 self 是 request 对象,当前代码是在 request.py 中 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() # 全部对象都为None,走这一步
def _not_authenticated(self): """ Set authenticator, user & authtoken representing an unauthenticated request. # 若是全部对象都为None,这里默认设置一个匿名用户 Defaults are None, AnonymousUser & None. """ self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # AnonymousUser else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() # None else: self.auth = None
以上即是须要掌握的源码流程,基于上面的思路,能够作一个登陆认证的示例
一、使用
BaseAuthentication
,实现 authenticate
方法AuthenticationFailed
异常,表示认证失败(元素1, 元素2)
,元素1
赋值给 request.user
,元素2
赋值给 request.auth
authentication_classes = [Authentication, ]
REST_FRAMEWORK
二、源码流程
先走 dispatch()
,对 request
进行封装,而后执行 initial
,在 initial
中进行认证。执行认证的流程是去找 request.user
,在 request.user
中找以前封装的 request
的全部认证对象,再循环全部的认证对象,执行 authenticate
方法