DRF版本和认证源码分析
request源码封装和版本
首先举个示例
#项目urls.py
urlpatterns = [
url(r'^api/(?P<version>\w+)/', include('api.urls')),
]
#app的urls.py
urlpatterns = [
url(r'^login/', account.LoginView.as_view()),
url(r'^article/', article.ArticleView.as_view()),
]
#settings.py
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
"ALLOWED_VERSIONS":['v1',]
}
#views.py
import uuid
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning
class LoginView(APIView):
"""
登录接口
"""
def post(self,request,*args,**kwargs):
user_object = models.UserInfo.objects.filter(**request.data).first()
if not user_object:
return Response('登录失败')
random_string = str(uuid.uuid4())
user_object.token = random_string
user_object.save()
# 如果成功给前端返回,随机字符串当token值
return Response(random_string)
版本源码分析
# 请求进来之后走APIView的dispatch方法
def dispatch(self, request, *args, **kwargs):
request = self.initialize_request(request, *args, **kwargs)
'''
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
class Request:
self._request = request
self.authenticators = authenticators or ()
'''
self.initial(request, *args, **kwargs)
'''
def initial(self, request, *args, **kwargs):
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
def determine_version(self, request, *args, **kwargs):
# 先去自定义类中找versioning_class,找不到在去父类找,
# 最后versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
if self.versioning_class is None:
return (None, None)
# 实例化版本类对象
scheme = self.versioning_class()
# 执行版本类中的determine_version方法,并把新request对象传进去
return (scheme.determine_version方法(request, *args, **kwargs), scheme)
# from rest_framework.versioning import URLPathVersioning
# URLPathVersioning中的determine_version方法
def determine_version(self, request, *args, **kwargs):
version = kwargs.get(self.version_param, self.default_version)
if version is None:
version = self.default_version
# 如果请求中的版本没有在settings定义中,那么报错
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version
'''
DRF认证流程
settings
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES":["kka.auth.TokenAuthentication",]
}
views
from rest_framework.views import APIView
class OrderView(APIView):
def get(self,request,*args,**kwargs):
if request.user:
return Response('order')
return Response('滚')
urls
urlpatterns = [
url(r'^login/$', views.LoginView.as_view()),
url(r'^order/$', views.OrderView.as_view()),
url(r'^user/$', views.UserView.as_view()),
]
认证源码分析
# 请求进来之后走APIView的dispatch方法
def dispatch(self, request, *args, **kwargs):
# 执行initialize_request
request = self.initialize_request(request, *args, **kwargs)
# 此中封装了老的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(),###### [MyAuthentication(),]
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# 循环authentication_classes,并生成对象列表
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes]
# 先去自定义类中寻找,如果没有就从settings中寻找
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
# 然后执行initial
self.initial(request, *args, **kwargs)
# 执行initial中perform_authentication方法
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)
# 执行新request.user类方法
def perform_authentication(self, request):
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
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators:
try:
# 执行自定义认证类下的authenticate方法,并返回一个元组
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
# 账号密码model对象和token分别赋值给user,auth
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
# 自定义认证类
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
token = request.query_params.get('token')
user_object = models.UserInfo.objects.filter(token=token).first()
if user_object:
# 验证账号密码在数据库中是否存在,存在则返回对象和token值
return (user_object,token)
return (None,None)