drf中认证源码流程
drf中认证流程
首先通过导入from rest_framework.views import APIView
,然后通过ctrl+鼠标右键进入到APIView类中,apiview中定义了许多方法,我们首先找到dispatch方法,因为定义路由时候,通过指定url找到对应的视图类,首先会执行dispatch方法
## dispatch源码
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# initialize_request() 返回初始请求对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# initial()处理请求方法之前要做的一些检查,其中就包括认证检查,权限检查,节流等
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
... # 此处代码省略,这部分代码主要就是用来获取适当的请求方法
然后我们点击self.initial(request, *args, **kwargs)
# 主要就是处理请求方法前的一些校验
def initial(self, request, *args, **kwargs):
....
# 重点关注这三个
# Ensure that the incoming request is permitted
self.perform_authentication(request) # 对传入请求做身份认证的
self.check_permissions(request) # 验证权限
self.check_throttles(request) # 节流
然后我们点击self.perform_authentication(request)
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 # 这边调用的是drf(APIView)的Request的user属性
然后我们点击user
(在rest_framework下的request.py文件)
#返回与当前请求关联的用户,作为已验证的用户,通过提供给请求的身份验证类。
@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
然后我们点击self._authenticate()
#开始用户认证,如果验证成功后返回元组: (用户,用户Token)
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
# [BasicAuthentication()对象,]
# 循环得到每个对象
for authenticator in self.authenticators: # 这里的self指的是drf的request对象,看下面的分析
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
self.user, self.auth = user_auth_tuple #返回一个元祖,user、auth
return
self._not_authenticated()
再看下self._not_authenticated()
#如果认证成功,执行_authenticate方法,若认证失败抛出异常调用self._not_authenticated()
def _not_authenticated(self):
"""
Set authenticator, user & authtoken representing an unauthenticated request.
Defaults are None, AnonymousUser & None.
"""
#如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
我们可以从APIView类中找到initialize_request()
函数,主要作用就是封装并返回初始化request对象
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
return Request(
request, # 封装了原生request
parsers=self.get_parsers(),
# [BasicAuthentication(),] #实例化对象
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
我们点击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] #实例化对象
我们点击self.authentication_classes
# api_settings文件中就是drf默认的验证器
class APIView(View):
...
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
...
我们点击api_settings.DEFAULT_AUTHENTICATION_CLASSES
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication', # session认证
'rest_framework.authentication.BasicAuthentication' # 基本认证
],
然后我们来看一下上面的两个认证器类(rest_framework/authentication.py)
# 导入
from rest_framework.authentication import BaseAuthentication
# 点开BaseAuthentication
# 可以看到这是一个父类,所有认证器类都需要继承它,并且需要重写里面的两个方法authenticate和authenticate_header
class BaseAuthentication:
"""
All authentication classes should extend BaseAuthentication.
"""
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise NotImplementedError(".authenticate() must be overridden.")
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
SessionAuthentication认证器类代码
class SessionAuthentication(BaseAuthentication):
"""
Use Django's session framework for authentication.
"""
def authenticate(self, request):
"""
Returns a `User` if the request session currently has a logged in user.
Otherwise returns `None`.
"""
# Get the session-based user from the underlying HttpRequest object
user = getattr(request._request, 'user', None)
# Unauthenticated, CSRF validation not required
if not user or not user.is_active:
return None
self.enforce_csrf(request)
# CSRF passed with authenticated user
return (user, None)
def enforce_csrf(self, request):
"""
Enforce CSRF validation for session based authentication.
"""
def dummy_get_response(request): # pragma: no cover
return None
check = CSRFCheck(dummy_get_response)
# populates request.META['CSRF_COOKIE'], which is used in process_view()
check.process_request(request)
reason = check.process_view(request, None, (), {})
if reason:
# CSRF failed, bail with explicit error message
raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)
所以我们要自定义认证类,只需要参考上面给出的代码,重写父类的两个方法即可,当然rest_framework/authentication.py这个文件里面还有BasicAuthentication,TokenAuthentication,RemoteUserAuthentication这个几个类的代码,也可以参考
自定义认证类
import logging
from django.conf import settings
from rest_framework.authentication import (
BaseAuthentication, get_authorization_header,
)
from rest_framework.exceptions import AuthenticationFailed, PermissionDenied
from six import raise_from
from .managers.pam import auth
from .models import User
logger = logging.getLogger(__name__)
class JWTAuthentication(BaseAuthentication):
# 默认会返回Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b,指定keyword则会返回使用指定的关键字Authorization: Jwt 9944b09199c62bcf941
keyword = 'Jwt'
# 自定义认证需要重写 authenticate 方法!
def authenticate(self, request):
# 由于 header 的头部是 byte 类型此方法 转换成 字符串 然后以空格为界 转换列表
# AUTHORIZATION這个就是之前服务端返回的,只不过Django会默认加上HTTP
auth = get_authorization_header(request).split()
# auth = ["Token", "c4840b5226a65806c586c239345fce66caf12409"]
if not auth or auth[0].lower() != self.keyword.lower().encode():
return None
if len(auth) == 1:
raise AuthenticationFailed(
detail='Invalid token header. No credentials provided.'
)
elif len(auth) > 2:
raise AuthenticationFailed(
detail='Invalid token header.'
'Token string should not contain spaces.'
)
try:
token = auth[1].decode()# token = c4840b5226a65806c586c239345fce66caf12409
except UnicodeError:
raise AuthenticationFailed(
detail='Invalid token header.'
'Token string should not contain invalid characters.'
)
return self.authenticate_credentials(token)
# token 认证!
def authenticate_credentials(self, token):
import jwt
from jwt import InvalidTokenError
try:
payload = jwt.decode(
token, settings.SECRET_KEY,
options={
'verify_signature': True,
'verify_exp': True,
'verify_nbf': True,
'verify_iat': True,
'require_exp': True,
'require_nbf': True,
'require_iat': True,
'require_iss': True,
'require_jti': True,
'require_role': True,
'require_sub': True,
'require_mgt': True
}
)
# sub: jwt所面向的用户
user = User.objects.get(username=payload['sub'])
payload_role = User.get_role_value(payload['role'])
if payload_role > user.role:
raise PermissionDenied(
'Insufficient permission.'
)
return user, payload
except InvalidTokenError as e:
raise_from(
AuthenticationFailed, e
)
except User.DoesNotExist as e:
raise_from(
AuthenticationFailed, e
)
# “jwt” 自定义的字符串 生成的token前面
def authenticate_header(self, request):
return self.keyword
class CookieAuthentication(JWTAuthentication):
def authenticate(self, request):
token = request.COOKIES.get('token')
if token is None:
return None
token = token.decode()
return self.authenticate_credentials(token)
视图类中使用
class view(APIView):
authentication_classes = (
JWTAuthentication,
CookieAuthentication
)
settings.py配置文件中需要指定一下使用我们自定义的类路径
REST_FRAMEWORK = {
# 认证器类
'DEFAULT_AUTHENTICATION_CLASSES': (
#'rest_framework.authentication.BasicAuthentication', # 基本认证
#'rest_framework.authentication.SessionAuthentication', # session认证
# 使用我们自定义的认证类
'antilles.user.plugins.JWTAuthentication'
),
}
参考链接
https://www.cnblogs.com/shi-qi/articles/9629399.html
https://www.cnblogs.com/jiakecong/p/14880244.html
https://www.cnblogs.com/u-damowang1/p/13554143.html
drf中认证源码流程的更多相关文章
- restful framework 认证源码流程
一.请求到来之后,都要先执行dispatch方法,dispatch方法方法根据请求方式的不同触发get/post/put/delete等方法 注意,APIView中的dispatch方法有很多的功能 ...
- Django后端项目----restful framework 认证源码流程
一.请求到来之后,都要先执行dispatch方法,dispatch方法方法根据请求方式的不同触发get/post/put/delete等方法 注意,APIView中的dispatch方法有很多的功能 ...
- Django rest_framework 认证源码流程
一.请求到来后,都要先执行dispatch方法 dispatch根据请求方式的不同触发get/post/put/delete等方法 注意,APIView中的dispatch方法有很多的功能 def d ...
- Rest Framework 认证源码流程
一.请求到来之后,都要先执行dispatch方法,dispatch方法方法根据请求方式的不同触发get/post/put/delete等方法 注意,APIView中的dispatch方法有很多的功能 ...
- Django drf:序列化增删改查、局部与全局钩子源码流程、认证源码分析、执行流程
一.序列化类的增.删.改.查 用drf的序列化组件 -定义一个类继承class BookSerializer(serializers.Serializer): -写字段,如果不指定source ...
- DRF cbv源码分析 restful规范10条 drf:APIView的源码 Request的源码 postman的安装和使用
CBV 执行流程 路由配置:url(r'^test/',views.Test.as_view()), --> 根据路由匹配,一旦成功,会执行后面函数(request) --> 本质就是执 ...
- Flask 源码流程,上下文管理
源码流程 创建对象 from flask import Flask """ 1 实例化对象 app """ app = Flask(__na ...
- Django缓存机制--rest_framework中节流源码使用的就是django提供的缓存api
一.配置缓存 https://www.jb51.net/article/124434.htm 二.缓存全站.页面.局部 三.自我控制的简单缓存API API 接口为:django.core.c ...
- Django session 源码流程
流程 Django session源码流程 首先执行的是SessionMiddleware的init方法 import_module(settings.SESSION_ENGINE) 导入了一个 dj ...
- Shiro 登录认证源码详解
Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...
随机推荐
- [转帖]enq: TX - row lock contention故障处理一则
https://www.cnblogs.com/zhchoutai/p/7088826.html 一个非常easy的问题,之所以让我对这个问题进行总结.一是由于没我想象的简单,在处理的过程中遇到了 ...
- Oracle 建立数据库dblink 然后同步部分表内容的总结
同步处理部分数据 背景 最近在项目上发现两个分库进行数据同步时部分内容同步存在问题. 最简单的方法是导表,但是害怕有其他关联信息异常, 所以同事想到了dblink的方式. 这里简单整理一下 同事用到的 ...
- 万能shell 简单查看已存在日志所有的启动记录
程序将日志 自动打包成了 gz 文件, 今天突然想查查所有的日志有没有相关关键字. 第一步解压缩所有的日志 cd 到相关目录 for i in `ls` ; do gzip -d $i ; done ...
- selenium四种截图方式
1.get_screenshot_as_file() from selenium import webdriver driver = webdriver.Chrome() driver.get(&qu ...
- 原生js中offsetTop, offsetLeft与offsetParent的详细讲解
简单说下:offsetTop offsetTop: 为只读属性. 返回的是一个数字. 它返回当前元素相对于其 offsetParent 元素的顶部内边距的距离. 它等价于offsetTop==> ...
- 大数据面试题集锦-Hadoop面试题(二)-HDFS
你准备好面试了吗?这里有一些面试中可能会问到的问题以及相对应的答案.如果你需要更多的面试经验和面试题,关注一下"张飞的猪大数据分享"吧,公众号会不定时的分享相关的知识和资料. 目录 ...
- 独立安装VS的C++编译器build tools
Microsoft C++ 生成工具 Microsoft C++ 生成工具 - Visual Studio Microsoft C++ 生成工具通过可编写脚本的独立安装程序提供 MSVC 工具集,无需 ...
- 人工智能自然语言处理:N-gram和TF-IDF模型详解
人工智能自然语言处理:N-gram和TF-IDF模型详解 1.N-gram 模型 N-Gram 是一种基于统计语言模型的算法.它的基本思想是将文本里面的内容按照字节进行大小为 N 的滑动窗口操作,形成 ...
- 【6】python生成数据曲线平滑处理——(Savitzky-Golay 滤波器、convolve滑动平均滤波)方法介绍,推荐玩强化学习的小伙伴收藏
相关文章: Python xlwt数据保存到 Excel中以及xlrd读取excel文件画图 先上效果图: 由于高频某些点的波动导致高频曲线非常难看,为了降低噪声干扰,需要对曲线做平滑处理,让曲线过 ...
- C/C++ Npcap包实现ARP欺骗
npcap 是Nmap自带的一个数据包处理工具,Nmap底层就是使用这个包进行收发包的,该库,是可以进行二次开发的,不过使用C语言开发费劲,在进行渗透任务时,还是使用Python构建数据包高效,唯一的 ...