源码剖析Django REST framework的认证方式及自定义认证

简介: ## 源码剖析Django REST framework的认证方式由Django的CBV模式流程,可以知道在`url匹配完成后,会执行自定义的类中的as_view方法`。如果自定义的类中没有定义`as_view方法`,根据面向对象中类的继承可以知道,则`会执行其父类View中的as_view方法``在Django的View的as_view方法中,又会调用dispatch方法`。
## 源码剖析Django REST framework的认证方式 由Django的CBV模式流程,可以知道在`url匹配完成后,会执行自定义的类中的as_view方法`。 如果自定义的类中没有定义`as_view方法`,根据面向对象中类的继承可以知道,则`会执行其父类View中的as_view方法` `在Django的View的as_view方法中,又会调用dispatch方法`。 现在来看看Django restframework的认证流程 > Django restframework是基于Django的框架,所以基于CBV的模式也会执行自定义的类中的as_view方法 先新建一个项目,配置url from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^user/', views.UserView.as_view()), ] views.py文件内容 from django.shortcuts import render,HttpResponse from rest_framework.views import APIView class UserView(APIView): def get(self,request,*args,**kwargs): print(request.__dict__) print(request.user) return HttpResponse("UserView GET") def post(self,request,*args,**kwargs): return HttpResponse("UserView POST") 启动项目,用浏览器向`http://127.0.0.1:8000/user/`发送get请求 ![](https://images2018.cnblogs.com/blog/1133627/201808/1133627-20180825183747075-1935268768.png) 可以知道请求发送成功。现在来看看源码流程,由于UserView继承APIView,查看APIView中的as_view方法 class APIView(View): ... @classmethod def as_view(cls, **initkwargs): if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): def force_evaluation(): raise RuntimeError( 'Do not evaluate the `.queryset` attribute directly, ' 'as the result will be cached and reused between requests. ' 'Use `.all()` or call `.get_queryset()` instead.' ) cls.queryset._fetch_all = force_evaluation view = super(APIView, cls).as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs return csrf_exempt(view) `通过super来执行APIView的父类Django的View中的as_view方法`。上一篇文章[源码解析Django CBV的本质](https://www.cnblogs.com/renpingsheng/p/9531649.html)中已经知道,View类的as_view方法会调用dispatch方法。 View类的as_view方法源码如下所示 class View(object): ... @classonlymethod def as_view(cls, **initkwargs): ... def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) ... `as_view方法中的self实际上指的是自定义的UserView这个类`,上面的代码会执行UserView类中dispatch方法。 由于UserView类中并没有定义dispatch方法,而UserView类继承自Django restframework的APIView类,所以会执行APIView类中的dispatch方法 def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs) if request.method.lower() in self.http_method_names: 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 可以看到,`先执行initialize_request方法处理浏览器发送的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 ) 在initialize_request方法里,把浏览器发送的request和restframework的处理器,认证,选择器等对象列表作为参数实例化Request类中得到新的request对象并返回,其中跟认证相关的对象就是authenticators。 def get_authenticators(self): """ Instantiates and returns the list of authenticators that this view can use. """ return [auth() for auth in self.authentication_classes] `get_authenticators方法通过列表生成式得到一个列表,列表中包含认证类实例化后的对象` 在这里,`authentication_classes来自于api_settings的配置` authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES 通过查看api_settings的源码可以知道,可以在项目的settings.py文件中进行认证相关的配置 api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) def reload_api_settings(*args, **kwargs): setting = kwargs['setting'] if setting == 'REST_FRAMEWORK': api_settings.reload() Django restframework通过initialize_request方法对原始的request进行一些封装后实例化得到新的request对象 然后执行initial方法来处理新得到的request对象,再来看看initial方法中又执行了哪些操作 def initial(self, request, *args, **kwargs): self.format_kwarg = self.get_format_suffix(**kwargs) neg = self.perform_content_negotiation(request) request.accepted_renderer, request.accepted_media_type = neg version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request) 由上面的源码可以知道,在initial方法中,`执行perform_authentication来对request对象进行认证操作` def perform_authentication(self, request): request.user `perform_authentication方法中调用执行request中的user方法`,`这里的request是封装了原始request,认证对象列表,处理器列表等之后的request对象` class Request(object): ... @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 从request中获取`_user`的值,如果获取到则执行`_authenticate方法`,否则返回`_user` 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.authenticators`实际上是`get_authenticators`方法执行完成后返回的对象列表 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 self.parsers = parsers or () self.authenticators = authenticators or () ... 循环认证的对象列表,`执行每一个认证方法的类中的authenticate方法`,得到通过认证的用户及用户的口令的元组,并返回元组完成认证的流程 在`_authenticate`方法中使用了try/except方法来捕获authenticate方法可能出现的异常 如果出现异常,就调用`_not_authenticated`方法来设置返回元组中的用户及口令并终止程序继续运行 总结,Django restframework的认证流程如下图 ![](https://images2018.cnblogs.com/blog/1133627/201808/1133627-20180825184058007-932847314.jpg) ## Django restframework内置的认证类 在上面的项目例子中,在UsersView的get方法中,打印`authentication_classes`和`request._user`的值 class UserView(APIView): # authentication_classes = [MyAuthentication,] def get(self,request,*args,**kwargs): print('authentication_classes:', self.authentication_classes) print(request._user) return HttpResponse("UserView GET") 打印结果为 authentication_classes: [
目录
相关文章
|
7月前
|
前端开发 API 数据格式
Django的restframework接口框架自定义返回数据格式
在前后端分离是大趋势的背景下,前端获取数据都是通过调用后台的接口来获取数据微服务的应用越来越多。Django是Python进行web应用开发常用的web框架,用Django框架进行web应用框架减少了很多工作,通常用很少量的代码就可以实现数据的增、删、改、查的业务应用,同样用Django的restframework的框架对外发布接口也是非常的简单方便,几行代码就可以将数据对象通过接口的方式提供服务。因为在实际开发过程中接口的返回数据有一定的格式,本文介绍通过自定义Response返回对象来自定义接口返回数据格式。
82 1
|
9天前
|
数据处理 数据库 开发者
Django中的自定义管理命令:扩展管理功能的途径
【4月更文挑战第15天】Django教程:介绍如何创建和使用自定义管理命令以扩展框架功能。在应用的`management/commands`目录下创建Python文件,继承`BaseCommand`,实现`handle`方法。示例代码展示了如何定义参数和执行逻辑。自定义命令适用于批量数据处理、定期任务、项目初始化和自定义迁移操作。注意文件位置、命令安全性和稳定性。自定义管理命令能提升开发和维护效率。
|
9月前
|
Python
【Django学习】(十六)session_token认证过程与区别_响应定制
【Django学习】(十六)session_token认证过程与区别_响应定制
|
4月前
|
JSON API 网络架构
Python Web 开发: 解释 Django REST framework 的作用,以及如何定义序列化器(Serializer)?
Python Web 开发: 解释 Django REST framework 的作用,以及如何定义序列化器(Serializer)?
|
7月前
|
API 网络架构 开发者
深入探索 Django Rest Framework
深入探索 Django Rest Framework
60 0
|
9月前
|
JSON API 数据安全/隐私保护
【Django学习】(十五)API接口文档平台_项目流程分析_日志器_认证_授权
【Django学习】(十五)API接口文档平台_项目流程分析_日志器_认证_授权
|
9月前
|
网络架构 Python
【Django学习】(十四)自定义action_router
【Django学习】(十四)自定义action_router
|
9月前
|
Python
【Django学习】(九)自定义校验器_单字段_多字段校验_模型序列化器类
【Django学习】(九)自定义校验器_单字段_多字段校验_模型序列化器类
|
9月前
|
数据库 网络架构 Python
18-Django REST framework-使用Django开发REST 接口
18-Django REST framework-使用Django开发REST 接口
|
11月前
|
数据库 Python
django drf 实现只有超级用户才能注册账号(涉及自定义权限permissions,获取token信息解析token信息)
django drf 实现只有超级用户才能注册账号(涉及自定义权限permissions,获取token信息解析token信息)