源码剖析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: [
目录
相关文章
|
2月前
|
数据库 Python
django中数据库外键可以自定义名称吗
django中数据库外键可以自定义名称吗
|
3月前
|
安全 数据库 数据安全/隐私保护
|
3月前
|
JSON API 数据安全/隐私保护
哇塞!Django REST framework 太逆天啦!构建 API 服务从未如此轻松,你还不来试试?
【8月更文挑战第31天】Django REST framework(DRF)是基于Django框架的高效Web API开发工具,提供序列化、视图集、路由等功能,简化API构建流程。使用DRF可轻松实现数据的序列化与反序列化,并支持权限管理和认证机制以保障API安全。安装DRF只需通过`pip install djangorestframework`命令。要创建基本项目,先安装Django并创建新应用,定义模型、序列化器及视图集,最后配置路由。测试API时,可通过Postman发送HTTP请求验证功能。无论项目大小,DRF均能提供强大支持。
42 0
|
3月前
|
SQL Shell API
python Django教程 之 模型(数据库)、自定义Field、数据表更改、QuerySet API
python Django教程 之 模型(数据库)、自定义Field、数据表更改、QuerySet API
|
3月前
|
中间件 API 网络架构
Django后端架构开发:从匿名用户API节流到REST自定义认证
Django后端架构开发:从匿名用户API节流到REST自定义认证
43 0
|
3月前
|
JSON API 网络架构
Django 后端架构开发:DRF 高可用API设计与核心源码剖析
Django 后端架构开发:DRF 高可用API设计与核心源码剖析
72 0
|
3月前
|
开发框架 JavaScript 前端开发
django快速实现个人博客(附源码)
Django作为一款成熟的Python Web开发框架提供了丰富的内置功能,如ORM(对象关系映射)、Admin管理界面、URL分发、模板系统、表单处理等,使得开发者能够快速搭建Web应用,大幅提高了开发效率。下面介绍如何快速的通过django模板系统快速实现个人博客。
64 0
|
22天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
120 45
|
23天前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
35 2
|
26天前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
36 1