rest-framework框架 -- 认证权限流程源码
认证权限
解析BaseAuthentication源码
# 做认证权限
from rest_framework import exceptions
from ..models import * class MyAuthentication(object):
def authenticate(self,request):
token = request._request.GET.get('token')
user_token_obj = UserToken.objects.filter(token=token).first()
if user_token_obj:
return user_token_obj.user,token
else:
raise exceptions.AuthenticationFailed("TOKEN验证失败") def authenticate_header(self,request):
pass # 上面需要写
# def authenticate_header(self,request): # 验证失败的
# pass
# BaseAuthentication源码 from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from ..models import * class MyAuthentication(BaseAuthentication):
def authenticate(self,request):
token = request._request.GET.get('token')
user_token_obj = UserToken.objects.filter(token=token).first()
if user_token_obj:
return user_token_obj.user,token
else:
raise exceptions.AuthenticationFailed("TOKEN验证失败")
源码帮你搞定了- -
class BaseAuthentication(object):
"""
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
关于认证权限源码解剖
1:从上篇文章可看出这里的类只要继承了APIView 都会执行到dispatch方法,要记住执行到dispatch方法,这里的dispatch是APIvie的里面的
执行dispatch方法时,先走self.initialize方法
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(),#解析数据,默认的有三种方式,
#self.get_authenticator优先找自己的,没有就找父类的
authenticators=self.get_authenticators(), # 实例化用户认证的对象,封装到request对象中去
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
2:获取认证相关的类的具体 authenticators=self.get_authenticators(),
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
# 实例化auth
return [auth() for auth in self.authentication_classes] # 返回的是列表[MyAuthentication()]
3:跑到查看认证的类
class APIView(View):
# The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES # 默认的验证权限
4:查看默认的验证api_settings(自带默认一般没什么用,pass)
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
由 DEFAULTS进
DEFAULTS = {
'DEFAULT_AUTHENTICATION_CLASSES': ( # 默认认证权限
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
),
}
5:问题:认证完返回什么内容? 继续源码解析
from rest_framework.authentication import BaseAuthentication
从authentication进去
查看到之前它默认的类了(利用这个就知道我们定制需要返回什么内容)
class BaseAuthentication(object):
"""
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
具体处理认证,从headers里面能获取用户名和密码
class BasicAuthentication(BaseAuthentication):
"""
HTTP Basic authentication against username/password.
"""
www_authenticate_realm = 'api' def authenticate(self, request):
"""
Returns a `User` if a correct username and password have been supplied
using HTTP Basic authentication. Otherwise returns `None`.
"""
auth = get_authorization_header(request).split() if not auth or auth[0].lower() != b'basic':
return None #返回none不处理。让下一个处理 if len(auth) == 1:
msg = _('Invalid basic header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid basic header. Credentials string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg) try:
auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')
except (TypeError, UnicodeDecodeError, binascii.Error):
msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
raise exceptions.AuthenticationFailed(msg) userid, password = auth_parts[0], auth_parts[2] # 返回用户和密码
return self.authenticate_credentials(userid, password, request) def authenticate_credentials(self, userid, password, request=None):
"""
Authenticate the userid and password against username and password
with optional request for context.
"""
credentials = {
get_user_model().USERNAME_FIELD: userid,
'password': password
}
user = authenticate(request=request, **credentials) if user is None:
raise exceptions.AuthenticationFailed(_('Invalid username/password.')) if not user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) return (user, None) def authenticate_header(self, request):
return 'Basic realm="%s"' % self.www_authenticate_realm
认证权限的具体步骤
1:直接调到执行dispatch方法,到初始化initial
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
# 认证
self.perform_authentication(request)
# 权限
self.check_permissions(request)
# 频率
self.check_throttles(request)
2:self.perform_authentication(request)
def perform_authentication(self, request):
request.user # 封装 后的request对象将会执行user方法
3:执行request user方法APIview里面的Rquest找到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'): # 反射 看request对象是否有’_user'
with wrap_attributeerrors():
self._authenticate()
return self._user # 返回user
4:执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)
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
self.user, self.auth = user_auth_tuple #返回一个元组,user,和auth,赋给了self,
# 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了
return self._not_authenticated()
5:在user_auth_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法
6:如果用户没有认证成功: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() # 默认值为:匿名用户AnonymousUser
else:
self.user = None # None 表示跳过该认证 if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN() # 默认值为:None
else:
self.auth = None # (user, token)
# 表示验证通过并设置用户名和Token;
# AuthenticationFailed异常
1: url(r"books/$",views.BookView.as_view(),name="book_list"),
as_view()
2: @classmethod
def as_view(cls, **initkwargs):
"""
Store the original class on the view function. This allows us to discover information about the view when we do URL
reverse lookups. Used for breadcrumb generation.
"""
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 # Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
return csrf_exempt(view) 3: return csrf_exempt(view)
url(r"books/$",view),
调用view 4: view = super(APIView, cls).as_view(**initkwargs)
找aipview的as_view 5: 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)
6:调dispatch
这里的dispatch是APIvie的 7:走dispatch的 self.initial(request, *args, **kwargs) 初始化 8: 走认证
# 认证
self.perform_authentication(request) 9: 进 认证perform_authentication 10: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 # 封装后的request对象将会执行user方法
user为静态方法 要从request里面调用user. 11: return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(), # 实例化用户认证的对象,封装到request对象中去
negotiator=self.get_content_negotiator(),
parser_context=parser_context
) 11.1
authenticators=self.get_authenticators(), # 实例化用户认证的对象,封装到requ 11.2
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes]
取出auth 然后auth() 实例化 ,---》 [MyAuthentication()]
调用自定义的验证 12
Request进去
@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'): # 反射 看request对象是否有’_user'
with wrap_attributeerrors():
self._authenticate()
return self._user 13 @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'): # 反射 看request对象是否有’_user'
with wrap_attributeerrors():
self._authenticate()
return self._user 14 self._authenticate() def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
这里self --- 》 request
for authenticator in self.authenticators: # 执行[auth() for auth in self.authentication_classes]
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._not_authenticated()
上面的request 返回了用户名,及信息 15 self.authenticators: 找到默认权限源码
0
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
# 认证
self.perform_authentication(request)
1:调用request user 找到request下的user方法
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 # 封装 后的request对象将会执行user方法
2:进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'): # 反射 看request对象是否有’_user'
with wrap_attributeerrors():
self._authenticate() # 执行_authenticate()
return self._user
2.1 self._authenticate()
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators: # 执行[auth() for auth in self.authentication_classes] authenticators 这个变量决定我们调用哪些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._not_authenticated() 到这里是从request类找过来
2.2
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 ()
authenticators 在init初始化有赋值
接着看哪里给他赋值
2.3
class APIView(View):
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(), # 实例化用户认证的对象,封装到request对象中去
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
authenticators=self.get_authenticators(),在这里赋值
3:
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
# 实例auth 找我们是否定义了authentication_classes没有往上找
return [auth() for auth in self.authentication_classes] # [MyAuthentication()] 4:self.authentication_classes
class APIView(View): # The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES # 默认的验证权限 5:
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES 6:api_settings
self.user = api_settings.UNAUTHENTICATED_USER() api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) 6:里面默认的2个方法
DEFAULTS 默认的全局
def reload_api_settings(*args, **kwargs):
setting = kwargs['setting']
if setting == 'REST_FRAMEWORK':
api_settings.reload()
rest-framework框架 -- 认证权限流程源码的更多相关文章
- 5.Spark Streaming流计算框架的运行流程源码分析2
1 spark streaming 程序代码实例 代码如下: object OnlineTheTop3ItemForEachCategory2DB { def main(args: Array[Str ...
- django的rest framework框架——认证、权限、节流控制
一.登录认证示例 模拟用户登录,获取token,当用户访问订单或用户中心时,判断用户携带正确的token,则允许查看订单和用户信息,否则抛出异常: from django.conf.urls impo ...
- Flask框架整个流程源码解读
Flask框架整个流程源码解读 一.总的流程 运行Flask其本质是运行Flask对象中的__call__,而__call__本质调用wsgi_app的方法 wsgi_app方法 def wsgi_a ...
- 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码
Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...
- [Android]从Launcher开始启动App流程源码分析
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5017056.html 从Launcher开始启动App流程源码 ...
- [Android]Android系统启动流程源码分析
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5013863.html Android系统启动流程源码分析 首先 ...
- Android笔记--View绘制流程源码分析(一)
Android笔记--View绘制流程源码分析 View绘制之前框架流程分析 View绘制的分析始终是离不开Activity及其内部的Window的.在Activity的源码启动流程中,一并包含 着A ...
- Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)
上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...
- SpringSecurity 初始化流程源码
SpringSecurity 初始化流程源码 本篇主要讲解 SpringSecurity初始化流程的源码部分,包括核心的 springSecurityFilterChain 是如何创建的,以及在介绍哪 ...
随机推荐
- [CF730J]Bottles
题目大意:每个瓶子有一定的容积,以及一定的水量,问最少几个瓶子装满所有水,在此基础上还要最小化移动水的体积 第一问用贪心直接求第二问转化成背包问题设dp[i][j]表示前i桶水总容积为j的最多水量,这 ...
- Commons Configuration之三Properties文件
转载自(https://my.oschina.net/u/2000201/blog/486653) Properties文件是流行的应用程序配置文件.当然,Commons Configuration支 ...
- 在Windows下使用Navicat连接Linux下的MySql
Linux下的Mysql安装可以参考菜鸟教程:https://www.runoob.com/mysql/mysql-install.html 安装完成后你会发现用Navicat链接MySql会失败,这 ...
- 迟到的thuwc&noiwc2018总结
已经4个多月没写博客了呢. thuwc和noiwc都炸了,接下来的一段时间都没怎么写题,靠文化课和游戏麻醉自己.这篇博客也算是向之前自闭.颓废的自己告别吧.. 先写一发游记: thuwc:Day1炸, ...
- linux:将job放在后台执行的方法
本文转自http://www.ibm.com/developerworks/cn/linux/l-cn-nohup/ 我自己在工作需要远程连到公司的开发机,在开发机上运行程序时,一旦退出终端就会导致运 ...
- 在 Linux 服务器上搭建和配置 Hadoop 集群
实验条件:3台centos服务器,jdk版本1.8.0,Hadoop 版本2.8.0 注:hadoop安装和搭建过程中都是在用户lb的home目录下,master的主机名为host98,slave的主 ...
- spring mvc: 资源绑定视图解析器(不推荐)
spring mvc: 资源绑定视图解析器(不推荐) 不适合单控制器多方法访问,有知道的兄弟能否告知. 访问地址: http://localhost:8080/guga2/hello/index 项目 ...
- 搞懂分布式技术11:分布式session解决方案与一致性hash
搞懂分布式技术11:分布式session解决方案与一致性hash session一致性架构设计实践 原创: 58沈剑 架构师之路 2017-05-18 一.缘起 什么是session? 服务器为每个用 ...
- 如何把数字字符'1'转换为整数(java 实现)
在一些表达式计算时,如 “3+2” 表达式自身是个字符串,通过切片得到的是数字字符和操作符,不能直接进行计算,在表达式计算中需要进行一步操作是,把数字字符'2','3'转化为整数. 如何操作? ...
- Anaconda Install
Linux 安装 首先下载Anaconda Linux安装包,然后打开终端输入: bash ~/Downloads/Anaconda3-2.4.0-Linux-x86_64.sh 注意:如果你接受默认 ...