ok,又到了看源码的时间了,今天我们看的源码是 SessionAuthentication 类
这一源码函数较少,比较简单,首先看到 authenticate 函数:
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)
多行注释的译文大概是:
- 如果请求会话当前有登录用户,则返回“User”。
- 否则返回“None”。
好了,清晰明了,这一段解释的是 user = getattr(request._request, 'user', None) 这一语句,
request._request 来自于 site-packages \ rest_framework \ request.py,它在文件中的语句是:
科普一下,getattr() 函数的用法:getattr(object, name[, default])
在这里,我们通过使用 getattr 来获取 request 中的 user 属性,如果有这一属性,说明用户已经登录了,将 ‘user’ 属性的值 传递给 user,如果没有这一属性,说明用户未登录,传递 None。继续往下看:
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)
if 语句可以忽略不看,大意是:
==>如果 用户不存在 或者 用户处于 非活跃状态 :
==> 返回 空
接着我们可以先不看 self.enforce_csrf(request)
最后,返回 user
再往下看:self.enforce_csrf(request),找到对应的函数:
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)
首先是 dummy_get_response 函数,这个函数直接看翻译就能理解它的作用 ( 假装获取响应 ),返回一个空值。
再往下看: CSRFCheck(dummy_get_response)
class CSRFCheck(CsrfViewMiddleware):
def _reject(self, request, reason):
# Return the failure reason instead of an HttpResponse
return reason
reject (拒绝) 函数,返回一个 reason (解释)
这里没什么意思,回过头来看下一句:check.process_request(request),
找到 process_request 函数:
def process_request(self, request):
csrf_token = self._get_token(request)
if csrf_token is not None:
# Use same token next time.
request.META['CSRF_COOKIE'] = csrf_token
好,重点来了,敲黑板,我们找到 _get_token 函数:
def _get_token(self, request):
if settings.CSRF_USE_SESSIONS:
try:
return request.session.get(CSRF_SESSION_KEY)
except AttributeError:
raise ImproperlyConfigured(
'CSRF_USE_SESSIONS is enabled, but request.session is not '
'set. SessionMiddleware must appear before CsrfViewMiddleware '
'in MIDDLEWARE.'
)
else:
try:
cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
except KeyError:
return None
csrf_token = _sanitize_token(cookie_token)
if csrf_token != cookie_token:
# Cookie token needed to be replaced;
# the cookie needs to be reset.
request.csrf_cookie_needs_reset = True
return csrf_token
乍一看,好像有很多的内容,实际上,我们根据 CSRF_USE_SESSIONS 将它拆开来看:
如果 CSRF_USE_SESSIONS 启用,我们返回 session 中的 ‘_csrftoken’ 属性 的值CSRF_SESSION_KEY = '_csrftoken'
如果 CSRF_USE_SESSIONS 未启用,返回一个 csrf_token
这一块不太好说明,我修改了部分后端代码,以及在源码中加了点东西以方便我们更直观的看到效果,直接上图:
这里我尝试的是:曾经登录过的用户在未登录的情况下访问页面,打印出来的数据,也就是请求头中的 Cookie.csrftoken 的数据是上一次登录时产生的 ‘csrf_token’
接着是登录后:
可以很明显的看出 _get_token 这一函数只是为了新建一个 csrf_token ,回过头,我们再看一下 _sanitize_token 函数,直译过来是 ‘审查令牌’ 意思。
def _sanitize_token(token):
# Allow only ASCII alphanumerics
if re.search('[^a-zA-Z0-9]', token):
return _get_new_csrf_token()
elif len(token) == CSRF_TOKEN_LENGTH:
return token
elif len(token) == CSRF_SECRET_LENGTH:
# Older Django versions set cookies to values of CSRF_SECRET_LENGTH
# alphanumeric characters. For backwards compatibility, accept
# such values as unmasked secrets.
# It's easier to mask here and be consistent later, rather than add
# different code paths in the checks, although that might be a tad more
# efficient.
return _mask_cipher_secret(token)
return _get_new_csrf_token()
这里跟你们说明一下:
- CSRF_SECRET_LENGTH = 32
- CSRF_TOKEN_LENGTH = 2 * CSRF_SECRET_LENGTH
以及 _get_new_csrf_token() 和 _mask_cipher_secret() 函数,他们内部的函数调用是相仿的,最终都是返回一个 ‘令牌’,算是 django 中的一种向后兼容的方式。
Session 验证类 概述:
在我们使用该类时,会筛选掉一批非法用户(无用户,非活跃用户),防止为其创建 csrf_token ,接着,就会通过其中的 self.enforce_csrf(request) 语句来为当前登录用户创建一个 csrf_token 并赋值给 CSRF_COOKIE 用来应对后续的验证。
好了,关于 SessionAuthentication 的源码部分就到这里了。
#Ps:属实是有些云里雾里的感觉,后续有机会再琢磨琢磨😂