前言
最近在研究學(xué)習(xí)django rest framework中的用戶登錄的權(quán)限和驗證方面基礎(chǔ),想結(jié)合源碼總結(jié)一下次询。
問題場景
在一個網(wǎng)頁中彰檬,比如博客,通過一個URL請求某個文章乔询,后臺系統(tǒng)中會判斷請求用戶中能否有權(quán)限進(jìn)行訪問蔬蕊,一般做法都會是獲取客戶端中的cookie信息,來進(jìn)行驗證是否有權(quán)限。
原理
我們從瀏覽器發(fā)出一個請求 Request岸夯,得到一個響應(yīng)后的內(nèi)容 HttpResponse 麻献,這個請求傳遞到 Django的過程是通過middleware來實現(xiàn),在settings.py中設(shè)置的middleware中的process_request
和process_response
依次執(zhí)行猜扮,接著再執(zhí)行后臺視圖函數(shù)勉吻。這篇文章主要講解用戶驗證就是SessionMiddleware
和AuthenticationMiddleware
。
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
步驟:
SessionMiddleware部分
/django/contrib/sessions/middleware.py
1.先依次加載上面中的middleware中有重載process_request
和process_response
2.process_request
會攔截用戶的cookie旅赢,把cookie中的信息放進(jìn)去request.session中
class SessionMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
request.session = self.SessionStore(session_key)
def process_response(self, request, response):
"""
If request.session was modified, or if the configuration is to save the
session every time, save the changes and set a session cookie or delete
the session cookie if the session has been emptied.
"""
try:
accessed = request.session.accessed
modified = request.session.modified
empty = request.session.is_empty()
except AttributeError:
pass
else:
# First check if we need to delete this cookie.
# The session should be deleted only if the session is entirely empty
if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
response.delete_cookie(
settings.SESSION_COOKIE_NAME,
path=settings.SESSION_COOKIE_PATH,
domain=settings.SESSION_COOKIE_DOMAIN,
)
else:
if accessed:
patch_vary_headers(response, ('Cookie',))
if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
if request.session.get_expire_at_browser_close():
max_age = None
expires = None
else:
max_age = request.session.get_expiry_age()
expires_time = time.time() + max_age
expires = http_date(expires_time)
# Save the session data and refresh the client cookie.
# Skip session save for 500 responses, refs #3881.
if response.status_code != 500:
try:
request.session.save()
except UpdateError:
raise SuspiciousOperation(
"The request's session was deleted before the "
"request completed. The user may have logged "
"out in a concurrent request, for example."
)
response.set_cookie(
settings.SESSION_COOKIE_NAME,
request.session.session_key, max_age=max_age,
expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
path=settings.SESSION_COOKIE_PATH,
secure=settings.SESSION_COOKIE_SECURE or None,
httponly=settings.SESSION_COOKIE_HTTPONLY or None,
samesite=settings.SESSION_COOKIE_SAMESITE,
)
return response
AuthenticationMiddleware部分
/django/contrib/auth/middleware.py
1.先在process_request
方法中判斷request中是否有session屬性字段齿桃,然后在get_uesr函數(shù)中調(diào)用auth.get_user方法,返回user煮盼,然后設(shè)置request.user
源碼:
def get_user(request):
if not hasattr(request, '_cached_user'):
request._cached_user = auth.get_user(request)
return request._cached_user
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
assert hasattr(request, 'session'), (
"The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE%s setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'."
) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
request.user = SimpleLazyObject(lambda: get_user(request))
def get_user(request):
"""
Return the user model instance associated with the given request session.
If no user is retrieved, return an instance of `AnonymousUser`.
"""
from .models import AnonymousUser
user = None
try:
user_id = _get_user_session_key(request)
backend_path = request.session[BACKEND_SESSION_KEY]
except KeyError:
pass
else:
if backend_path in settings.AUTHENTICATION_BACKENDS:
backend = load_backend(backend_path)
user = backend.get_user(user_id)
# Verify the session
if hasattr(user, 'get_session_auth_hash'):
session_hash = request.session.get(HASH_SESSION_KEY)
session_hash_verified = session_hash and constant_time_compare(
session_hash,
user.get_session_auth_hash()
)
if not session_hash_verified:
request.session.flush()
user = None
return user or AnonymousUser()
總結(jié)
settings.py中的middleware是對每個用戶請求做處理短纵,而drf中 BasicAuthentication
,SessionAuthentication僵控,TokenAuthentication是用來驗證用戶登錄信息的類香到,也就是用戶驗證信息上面的。對于TokenAuthentication驗證方式报破,這一篇文章有詳細(xì)介紹悠就。