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:属实是有些云里雾里的感觉,后续有机会再琢磨琢磨