Jiang's blog

DRF源码解析5--认证组件的封装和初始化

Word count: 812Reading time: 3 min
2020/02/24 Share

1.认证组件的初始化

在对DRF的版本认证里说到,initial()不仅对版本认证组件进行了初始化,同时还初始化了认证组件,现在来分析一下DRF是怎么样初始化认证方法的

1
2
def perform_authentication(self, request):
request.user

可以看到,perform_authentication()方法返回了request(相当于封装的Request),进入request中找到uesr方法

1.1 截取Request部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Request:

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 ()
self.negotiator = negotiator or self._default_negotiator()

@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user

@user.setter
def user(self, value):
# 当调用user时触发, 如user = 'xxx', 则value = 'xxx'
self._user = value
self._request.user = value

可以看到,user执行了self._authenticate方法,返回的_user为当前用户

截取self._authenticate的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
 def _authenticate(self):
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
return

self.authenticators为Request的属性,所以在init中可以找到

1
2
3
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self.authenticators = authenticators or ()

authenticators是作为参数传进来的,所以回到实例化Request的initialize_request方法中

1
2
3
4
5
6
7
8
9
10
def initialize_request(self, request, *args, **kwargs):
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
)

可以看到,authenticators传进了一个self.get_authenticators的方法

1.2 截取self.get_authenticators代码如下

1
2
def get_authenticators(self):
return [auth() for auth in self.authentication_classes]

可以看到,get_authenticators方法返回了self.authentication_classes中所有auth的执行结果的一个列表, 而self.authentication_classes则为DRF中默认的认证组件

authenticate

回到_authenticate方法中,现在已经知道authenticator是DRF默认的认证组件,则进去其authenticate方法中

1
2
3
4
5
6
7
8
class ForcedAuthentication:

def __init__(self, force_user, force_token):
self.force_user = force_user
self.force_token = force_token

def authenticate(self, request):
return (self.force_user, self.force_token)

其返回了self.force_user, self.force_token,分别为用户和验证用户信息的的token码,说明了认证组件都带有authenticate方法并且返回用户认证的信息

1.3 思路总结

DRF认证组件的初始化主要分为两部分:
3GsBTg.png


2. 认证组件的类型

DRF提供的认证组件在rest_framework.authentication
3GszAe.png

2.1 BaseAuthentication

1
2
3
4
5
6
7
class BaseAuthentication:

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

def authenticate_header(self, request):
pass

可以看出,authenticate方法就是自定制认证组件的钩子函数

2.2 SessionAuthentication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class SessionAuthentication(BaseAuthentication):

def authenticate(self, request):
# 重写了authenticate方法并获取当前的用户信息
# 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
# 执行enforce_csrf方法判断用户的csrf_token是否正确
self.enforce_csrf(request)

# CSRF passed with authenticated user
return (user, None)

def enforce_csrf(self, request):
check = CSRFCheck()
# populates request.META['CSRF_COOKIE'], which is used in process_view()
# 中间件的process_request方法,拿取用户的CSRF_COOKIE
check.process_request(request)
# 认证用户的CSRF_COOKIE是否正确
reason = check.process_view(request, None, (), {})
if reason:
# CSRF failed, bail with explicit error message
raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)

总结

DRF的认证组件就是通过中间件等方法,获取当前用户的认证信息,在与本地的信息进行对比,从而达到认证用户的目的。

CATALOG
  1. 1. 1.认证组件的初始化
    1. 1.1. 1.1 截取Request部分代码如下:
    2. 1.2. 截取self._authenticate的代码如下:
    3. 1.3. 1.2 截取self.get_authenticators代码如下
    4. 1.4. authenticate
    5. 1.5. 1.3 思路总结
  2. 2. 2. 认证组件的类型
    1. 2.1. 2.1 BaseAuthentication
    2. 2.2. 2.2 SessionAuthentication
  3. 3. 总结