REST framework 用户认证源码

REST 用户认证源码

在Django中,从URL调度器中过来的HTTPRequest会传递给disatch(),使用REST后也一样

# REST的dispatch
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 = argsself.kwargs = kwargsrequest = self.initialize_request(request, *args, **kwargs)self.request = requestself.headers = self.default_response_headers  # deprecate?try:self.initial(request, *args, **kwargs)# Get the appropriate handler methodif 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_allowedresponse = 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()重新分装了原来从URL调度器传来的request对象,并且返回的也是一个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对象

class Request(object):def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):passself._request = requestself.parsers = parsers or ()# ...

Request这个类使用"组合"将普通的httprequest分装在它的内部,除此之外还提供了用于身份验证的authenticators,用于解析请求内容的解析器(parsers)只关心authenticators

authenticators由self.get_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,并实例化authentication_classes中的对象加入到列表中返回

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

实际上authentication_classes只是一个包含认证类的列表


已经乱了,整理一下

首先,用户会生成一个httprequest,这个请求到URL调度器后会执行as_view()

path('shop/', views.ShopView.as_view())

而在as_view()中就会把这个原生的httprequest传递给dispatch()dispatch()中会对这个httprequest进一步封装,在这里具体就是增加了一个authenticators,他是一个列表,列表中是一系列从authentication_classes列表中实例化出来的对象。


然后进入try块,执行self.initial(request, *args, **kwargs),这条语句用来 “运行在调用方法处理程序之前需要发生的任何事情” 可以说是一个功能集合,聚合了认证管理,权限管理,版本控制等几个功能模块

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)

现在只关心用户认证的工作,进入perform_authentication(request)(现在的request已经是重新包装过的的request了),也只有一句话。

def perform_authentication(self, request):request.user

它调用了这个request对象的user属性,进入user,是一个属性方法,主体是调用了self._authenticate()

@property
def user(self):if not hasattr(self, '_user'):# 只是一个上下文管理器,方便清理之类的工作with wrap_attributeerrors():self._authenticate()return self._user

现在是那个封装过的request对象调用了自己的user属性方法,所以self已经是request了,之前是在视图(view.py)中自己定义的ShopView

进入self._authenticate()

    def _authenticate(self):for authenticator in self.authenticators:try:user_auth_tuple = authenticator.authenticate(self)except exceptions.APIException:self._not_authenticated()raiseif user_auth_tuple is not None:self._authenticator = authenticatorself.user, self.auth = user_auth_tuplereturnself._not_authenticated()

他会遍历self.authenticators,现在的self是那个分装过的request,所以self.authenticators其实就是上面列表生成式生成的那个认证类对象列表,它遍历并调用每一个认证类对象的authenticate方法,这个方法必须覆盖,否则会抛出NotImplementedError异常

def authenticate(self, request):raise NotImplementedError(".authenticate() must be overridden.")

这里的逻辑是一旦authenticate()抛出exceptions.APIException异常,就调用self._not_authenticated()也就是认证失败,如果没有抛出异常,就进入下面的if语句,判断返回值是否是None如果是,本次循环就结束,也就是不使用这个认证类对象,转而使用下一个认证类对象,如果不为None则进行一个序列解包操作,把元组中的第一个元素赋值给self.user第二个元素赋值给self.auth,终止循环,如果遍历完整个self.authenticators还是没认证成功,就会执行最后一行的self._not_authenticated()和认证时抛出异常一样,认证失败。

def _not_authenticated(self):"""设置authenticator,user&authToken表示未经过身份验证的请求。默认值为None,AnonymousUser&None。"""self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER()else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()else:self.auth = None

认证失败后的逻辑是:先看配置文件中有没有UNAUTHENTICATED_USER,如果有,就把这个配置内容作为默认的“匿名用户”,否则就把self.user赋值为None,self.auth也一样。


这大概就是认证的基本流程了。

过程总结

用户发出请求,产生request,传递到URL调度器,url调度器将request传递给as_view()as_view()再传递给dispatch(),在这里会给原来的request封装用来身份验证的authenticators,他是一个储存认证类对象的列表,封装完成后遍历这个列表,如果抛出exceptions.APIException异常,认证失败,使用匿名用户登录,否则如果返回一个二元组,就将他们分别赋值给user和auth,如果返回None,同样认证失败,使用匿名用户登录。

全局验证

可以设置对所有视图验证,因为

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
def reload_api_settings(*args, **kwargs):setting = kwargs['setting']if setting == 'REST_FRAMEWORK':api_settings.reload()

所以在Django的配置文件中添加

REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ['demo.utils.MyAuthentication.MyAuthentication']
}

就可以设置所有视图都要使用MyAuthentication验证,如果由别的视图不需要验证,可在视图类内把authentication_classes设置为空列表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/457530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

scrapyd部署_如何通过 Scrapyd + ScrapydWeb 简单高效地部署和监控分布式爬虫项目

来自 Scrapy 官方账号的推荐需求分析初级用户:只有一台开发主机能够通过 Scrapyd-client 打包和部署 Scrapy 爬虫项目,以及通过 Scrapyd JSON API 来控制爬虫,感觉 命令行操作太麻烦 ,希望能够通过浏览器直接部署和运行项目专业用…

最长上升子序列 (LIS算法(nlong(n)))

设 A[t]表示序列中的第t个数&#xff0c;F[t]表示从1到t这一段中以t结尾的最长上升子序列的长度&#xff0c;初始时设F [t] 0(t 1, 2, ..., len(A))。则有动态规划方程&#xff1a;F[t] max{1, F[j] 1} (j 1, 2, ..., t - 1, 且A[j] < A[t])。 现在&#xff0c;我们仔细…

牛顿插值--python实现

from tabulate import tabulate import sympy""" 牛顿插值法 """class NewtonInterpolation:def __init__(self, x: list, y: list):self.Xi = xself

css摇曳的_HTML5+CSS3实现树被风吹动摇晃

1新建html文档。2书写hmtl代码。3书写css代码。.trunk, .trunk div { background: #136086; width: 100px; height: 10px; position: absolute; left: 50%; top: 70%; margin-left: -10px; -webkit-animation-name: rot; animation-name: rot; -webkit-animation-duration: 2.0…

素数路(prime)

素数路(prime) 题目描述 已知一个四位的素数&#xff0c;要求每次修改其中的一位&#xff0c;并且要保证修改的结果还是一个素数&#xff0c;还不能出现前导零。你要找到一个修改数最少的方案&#xff0c;得到我们所需要的素数。 例如把1033变到8179&#xff0c;这里是一个最短…

python多线程单核_002_Python多线程相当于单核多线程的论证

很多人都说python多线程是假的多线程!下面进行论证解释:一、我们先明确一个概念&#xff0c;全局解释器锁(GIL)Python代码的执行由Python虚拟机(解释器)来控制。Python在设计之初就考虑要在主循环中&#xff0c;同时只有一个线程在执行&#xff0c;就像单CPU的系统中运行多个进…

detail:JSON parse error - Expecting value: line 1 column 1 (char 0)

detail":"JSON parse error - Expecting value: line 1 column 1 (char 0) 在调用接口时返回400错误&#xff0c;详情是 {detail":"JSON parse error - Expecting value: line 1 column 1 (char 0)"}原因是传送数据的格式有问题&#xff0c;不要使用…

【IDEA 2016】intellij idea tomcat jsp 热部署

刚开始用IDEA&#xff0c;落伍的我&#xff0c;只是觉得IDEA好看。可以换界面。想法如此的low。 真是不太会用啊&#xff0c;弄好了tomcat。程序启动竟然改动一下就要重启&#xff0c;JSP页面也一样。 IDEA可以配置热部署&#xff0c;打开tomcat配置页面&#xff0c;将红框处&a…

C# where用法解析

where 子句用于指定类型约束&#xff0c;这些约束可以作为泛型声明中定义的类型参数的变量。1.接口约束。例如&#xff0c;可以声明一个泛型类 MyGenericClass&#xff0c;这样&#xff0c;类型参数 T 就可以实现 IComparable<T> 接口&#xff1a;public class MyGeneric…

ubuntu进入桌面自动启动脚本_在 Ubuntu 下开机自启动自己的 QT 程序而不启动 Ubuntu 的桌面...

1. /etc/profile 方式实现这个功能&#xff0c;要完成两步&#xff1a;1、系统设置-> 用户账户-> 点击我的账户-> 点击右上角的解锁-> 打开自动登录-> 点击右上角的锁定-> 退出系统设置2、在 /etc/profile 文件的开头添加执行 qt 程序的命令。如&#xff1a;…

Java obj与JSON互转(jackson)

JSON 解析 常见的json解析器&#xff1a; jsonlibGson(谷歌)fastjson(阿里)jackson(Spring内置) jackson 依赖jar包 jackson-annotations/jackson-core/jackson-databind/ 官网下载地址 1. Java对象转JSON 1.1 核心对象 ObjectMapper 1.2常用转换方法 writeValue(参…

如何制作一个简单的APP应用软件?

如今随着移动智能手机的普及&#xff0c;让APP的市场一片繁荣&#xff0c;现在市场上的APP数量数不胜数&#xff0c;对于APP开发的我们很多外行人也许认为&#xff0c;开发APP是不是特别难&#xff0c;是不是只有资历很高的程序员才能够完成这个任务&#xff0c;或者说要想开发…

I/O重定向

每个进程都至少有3个信息&#xff1a;“标准输入”stdin、“标准输出”stdout、和“标准出错”stderr。标准输入通常来自键盘&#xff0c;标准输出和标准错误输出通常被发往屏幕&#xff08;并不会保存在磁盘文件中&#xff09;。有些时候&#xff0c;需要从文件读取输入&#…

java 自动装拆箱

title: “java 自动装拆箱” tags: Java 将基本数据类型封装成对象的过程叫做装箱&#xff08;boxing&#xff09;&#xff0c;反之基本数据类型对应的包装类转换为基本数据类型的过程叫做拆箱&#xff08;unboxing&#xff09;; 基本数据类型与其他对象的区别 基本数据类型 …

设计模式11---组合模式(Composite Pattern)

一、组合模式定义 将对象组合成树形结构以表示“部分-整体”的层次结构&#xff0c;使得用户对单个对象和组合对象的使用具有一致性。Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compos…

Linux 多核下绑定硬件中断到不同 CPU(IRQ Affinity)

转载 - Linux 多核下绑定硬件中断到不同 CPU&#xff08;IRQ Affinity&#xff09; 作者 digoal 日期 2016-11-20 标签 Linux , IRQ , 中断 , CPU亲和 , 绑定中断处理CPU 背景 原文 http://www.vpsee.com/2010/07/load-balancing-with-irq-smp-affinity/ 原文 硬件中断发生频繁…

请列举你了解的分布式锁_这几种常见的“分布式锁”写法,搞懂再也不怕面试官,安排!...

什么是分布式锁&#xff1f;大家好&#xff0c;我是jack xu&#xff0c;今天跟大家聊一聊分布式锁。首先说下什么是分布式锁&#xff0c;当我们在进行下订单减库存&#xff0c;抢票&#xff0c;选课&#xff0c;抢红包这些业务场景时&#xff0c;如果在此处没有锁的控制&#x…

leetcode 268

等差数列求值 1 class Solution {2 public:3 int missingNumber(vector<int>& nums) {4 int nnums.size();5 int kn*(n1)/2;6 for(int i0;i<n;i)7 k-nums[i];8 return k;9 } 10 }; 转载于:https://www.cnblogs.…

301缓存重定向?301 Moved Permanently (from disk cache)

今天在写一个博客系统时&#xff0c;发现首页数据经常刷新不出来&#xff0c;甚至后端根本就没有接受到这个请求&#xff0c;以为是Ajax的问题&#xff0c;但通过抓包发现Ajax请求确实已经发出去了&#xff0c;但状态码是 301 Moved Permanently (from disk cache),301是永久重…

Firefox 50优化Electrolysis

Mozilla正式发布Firefox 50。最新的版本中提升了来自多个内容进程用户的用户体验&#xff0c;并修复了十几个高影响的安全漏洞。\\在Firefox最新版本的变更中&#xff0c;我们注意到了它对于Electrolysis的进一步改进。Electrolysis是Mozilla实现在后台进程中呈现和执行web相关…